create-better-t-stack 2.22.4 → 2.22.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -27,12 +27,12 @@ Follow the prompts to configure your project or use the `--yes` flag for default
|
|
|
27
27
|
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
28
28
|
| **TypeScript** | End-to-end type safety across all parts of your application |
|
|
29
29
|
| **Frontend** | • React with TanStack Router<br>• React with React Router<br>• React with TanStack Start (SSR)<br>• Next.js<br>• SvelteKit<br>• Nuxt (Vue)<br>• SolidJS<br>• React Native with NativeWind (via Expo)<br>• React Native with Unistyles (via Expo)<br>• None |
|
|
30
|
-
| **Backend** | • Hono<br>• Express<br>• Elysia<br>• Next.js API routes<br>• Convex<br>• Fastify<br>• None
|
|
30
|
+
| **Backend** | • Hono<br>• Express<br>• Elysia<br>• Next.js API routes<br>• Convex<br>• Fastify<br>• None |
|
|
31
31
|
| **API Layer** | • tRPC (type-safe APIs)<br>• oRPC (OpenAPI-compatible type-safe APIs)<br>• None |
|
|
32
|
-
| **Runtime** | • Bun<br>• Node.js
|
|
32
|
+
| **Runtime** | • Bun<br>• Node.js<br>• Cloudflare Workers<br>• None |
|
|
33
33
|
| **Database** | • SQLite<br>• PostgreSQL<br>• MySQL<br>• MongoDB<br>• None |
|
|
34
34
|
| **ORM** | • Drizzle (TypeScript-first)<br>• Prisma (feature-rich)<br>• Mongoose (for MongoDB)<br>• None |
|
|
35
|
-
| **Database Setup** | • Turso (SQLite)<br>• Neon (PostgreSQL)<br>• Prisma Postgres (via Prisma Accelerate)<br>• MongoDB Atlas<br>• None (manual setup)
|
|
35
|
+
| **Database Setup** | • Turso (SQLite)<br>• Cloudflare D1 (SQLite)<br>• Neon (PostgreSQL)<br>• Supabase (PostgreSQL)<br>• Prisma Postgres (via Prisma Accelerate)<br>• MongoDB Atlas<br>• None (manual setup) |
|
|
36
36
|
| **Authentication** | Better-Auth (email/password, with more options coming soon) |
|
|
37
37
|
| **Styling** | Tailwind CSS with shadcn/ui components |
|
|
38
38
|
| **Addons** | • PWA support<br>• Tauri (desktop applications)<br>• Starlight (documentation site)<br>• Biome (linting and formatting)<br>• Husky (Git hooks)<br>• Turborepo (optimized builds) |
|
|
@@ -59,9 +59,9 @@ Options:
|
|
|
59
59
|
--package-manager <pm> Package manager (npm, pnpm, bun)
|
|
60
60
|
--install Install dependencies
|
|
61
61
|
--no-install Skip installing dependencies
|
|
62
|
-
--db-setup <setup> Database setup (turso, neon, prisma-postgres, mongodb-atlas, none)
|
|
62
|
+
--db-setup <setup> Database setup (turso, d1, neon, supabase, prisma-postgres, mongodb-atlas, none)
|
|
63
63
|
--backend <framework> Backend framework (hono, express, elysia, next, convex, fastify, none)
|
|
64
|
-
--runtime <runtime> Runtime (bun, node, none)
|
|
64
|
+
--runtime <runtime> Runtime (bun, node, workers, none)
|
|
65
65
|
--api <type> API type (trpc, orpc, none)
|
|
66
66
|
-h, --help Display help
|
|
67
67
|
```
|
|
@@ -104,6 +104,12 @@ Create a project with Turso database setup:
|
|
|
104
104
|
npx create-better-t-stack my-app --database sqlite --orm drizzle --db-setup turso
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
+
Create a project with Supabase PostgreSQL setup:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npx create-better-t-stack my-app --database postgres --orm drizzle --db-setup supabase --auth
|
|
111
|
+
```
|
|
112
|
+
|
|
107
113
|
Create a project with Convex backend:
|
|
108
114
|
|
|
109
115
|
```bash
|
|
@@ -116,10 +122,48 @@ Create a project with documentation site:
|
|
|
116
122
|
npx create-better-t-stack my-app --addons starlight
|
|
117
123
|
```
|
|
118
124
|
|
|
125
|
+
Create a minimal TypeScript project with no backend:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
npx create-better-t-stack my-app --backend none --frontend tanstack-router
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Create a backend-only project with no frontend:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
npx create-better-t-stack my-app --frontend none --backend hono --database postgres --orm drizzle
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Create a simple frontend-only project:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npx create-better-t-stack my-app --backend none --frontend next --addons none --examples none
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Create a Cloudflare Workers project:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
npx create-better-t-stack my-app --backend hono --runtime workers --database sqlite --orm drizzle --db-setup d1
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Create a minimal API-only project:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
npx create-better-t-stack my-app --frontend none --backend hono --api trpc --database none --addons none
|
|
153
|
+
```
|
|
154
|
+
|
|
119
155
|
## Compatibility Notes
|
|
120
156
|
|
|
121
157
|
- **Convex backend**: Automatically disables authentication, database, ORM, and API options
|
|
122
158
|
- **Backend 'none'**: If selected, this option will force related options like API, ORM, database, authentication, and runtime to 'none'. Examples will also be disabled (set to none/empty).
|
|
159
|
+
- **Frontend 'none'**: Creates a backend-only project. When selected, PWA, Tauri, and certain examples may be disabled.
|
|
160
|
+
- **API 'none'**: Disables tRPC/oRPC setup. Can be used with backend frameworks for REST APIs or custom API implementations.
|
|
161
|
+
- **Database 'none'**: Disables database setup. Automatically sets ORM to 'none' and disables authentication.
|
|
162
|
+
- **ORM 'none'**: Can be used when you want to handle database operations manually or use a different ORM.
|
|
163
|
+
- **Runtime 'none'**: Only available with Convex backend or when backend is 'none'.
|
|
164
|
+
- **Cloudflare Workers runtime**: Only compatible with Hono backend, Drizzle ORM (or no ORM), and SQLite database (with D1 setup). Not compatible with MongoDB.
|
|
165
|
+
- **Addons 'none'**: Skips all addons (PWA, Tauri, Starlight, Biome, Husky, Turborepo).
|
|
166
|
+
- **Examples 'none'**: Skips all example implementations (todo, AI chat).
|
|
123
167
|
- **SvelteKit, Nuxt, and SolidJS** frontends are only compatible with oRPC API layer
|
|
124
168
|
- **PWA support** requires React with TanStack Router, React Router, or SolidJS
|
|
125
169
|
- **Tauri desktop app** requires React (TanStack Router/React Router), Nuxt, SvelteKit, or SolidJS
|
package/dist/index.js
CHANGED
|
@@ -52,6 +52,7 @@ const dependencyVersionMap = {
|
|
|
52
52
|
"drizzle-orm": "^0.44.2",
|
|
53
53
|
"drizzle-kit": "^0.31.2",
|
|
54
54
|
"@libsql/client": "^0.15.9",
|
|
55
|
+
"@neondatabase/serverless": "^1.0.1",
|
|
55
56
|
pg: "^8.14.1",
|
|
56
57
|
"@types/pg": "^8.11.11",
|
|
57
58
|
mysql2: "^3.14.0",
|
|
@@ -93,7 +94,7 @@ const dependencyVersionMap = {
|
|
|
93
94
|
"@trpc/tanstack-react-query": "^11.4.2",
|
|
94
95
|
"@trpc/server": "^11.4.2",
|
|
95
96
|
"@trpc/client": "^11.4.2",
|
|
96
|
-
convex: "^1.
|
|
97
|
+
convex: "^1.25.0",
|
|
97
98
|
"@convex-dev/react-query": "^0.0.0-alpha.8",
|
|
98
99
|
"convex-svelte": "^0.0.11",
|
|
99
100
|
"@tanstack/svelte-query": "^5.74.4",
|
|
@@ -3416,7 +3417,12 @@ async function setupDatabase(config) {
|
|
|
3416
3417
|
devDependencies: ["drizzle-kit"],
|
|
3417
3418
|
projectDir: serverDir
|
|
3418
3419
|
});
|
|
3419
|
-
else if (database === "postgres") await addPackageDependency({
|
|
3420
|
+
else if (database === "postgres") if (dbSetup === "neon") await addPackageDependency({
|
|
3421
|
+
dependencies: ["drizzle-orm", "@neondatabase/serverless"],
|
|
3422
|
+
devDependencies: ["drizzle-kit"],
|
|
3423
|
+
projectDir: serverDir
|
|
3424
|
+
});
|
|
3425
|
+
else await addPackageDependency({
|
|
3420
3426
|
dependencies: ["drizzle-orm", "pg"],
|
|
3421
3427
|
devDependencies: ["drizzle-kit", "@types/pg"],
|
|
3422
3428
|
projectDir: serverDir
|
|
@@ -3573,19 +3579,15 @@ function generateReadmeContent(options) {
|
|
|
3573
3579
|
const { projectName, packageManager, database, auth, addons = [], orm = "drizzle", runtime = "bun", frontend = ["tanstack-router"], backend = "hono", api = "trpc" } = options;
|
|
3574
3580
|
const isConvex = backend === "convex";
|
|
3575
3581
|
const hasReactRouter = frontend.includes("react-router");
|
|
3576
|
-
const hasTanstackRouter = frontend.includes("tanstack-router");
|
|
3577
3582
|
const hasNative = frontend.includes("native-nativewind") || frontend.includes("native-unistyles");
|
|
3578
|
-
const hasNext = frontend.includes("next");
|
|
3579
|
-
const hasTanstackStart = frontend.includes("tanstack-start");
|
|
3580
3583
|
const hasSvelte = frontend.includes("svelte");
|
|
3581
|
-
const hasSolid = frontend.includes("solid");
|
|
3582
|
-
const hasNuxt = frontend.includes("nuxt");
|
|
3583
3584
|
const packageManagerRunCmd = packageManager === "npm" ? "npm run" : packageManager;
|
|
3584
3585
|
let webPort = "3001";
|
|
3585
3586
|
if (hasReactRouter || hasSvelte) webPort = "5173";
|
|
3587
|
+
const stackDescription = generateStackDescription(frontend, backend, api, isConvex);
|
|
3586
3588
|
return `# ${projectName}
|
|
3587
3589
|
|
|
3588
|
-
This project was created with [Better-T-Stack](https://github.com/AmanVarshney01/create-better-t-stack), a modern TypeScript stack
|
|
3590
|
+
This project was created with [Better-T-Stack](https://github.com/AmanVarshney01/create-better-t-stack), a modern TypeScript stack${stackDescription ? ` that combines ${stackDescription}` : ""}.
|
|
3589
3591
|
|
|
3590
3592
|
## Features
|
|
3591
3593
|
|
|
@@ -3615,18 +3617,14 @@ Then, run the development server:
|
|
|
3615
3617
|
${packageManagerRunCmd} dev
|
|
3616
3618
|
\`\`\`
|
|
3617
3619
|
|
|
3618
|
-
${
|
|
3619
|
-
${hasNative ? "Use the Expo Go app to run the mobile application.\n" : ""}
|
|
3620
|
-
${isConvex ? "Your app will connect to the Convex cloud backend automatically." : "The API is running at [http://localhost:3000](http://localhost:3000)."}
|
|
3620
|
+
${generateRunningInstructions(frontend, backend, webPort, hasNative, isConvex)}
|
|
3621
3621
|
|
|
3622
3622
|
${addons.includes("pwa") && hasReactRouter ? "\n## PWA Support with React Router v7\n\nThere is a known compatibility issue between VitePWA and React Router v7.\nSee: https://github.com/vite-pwa/vite-plugin-pwa/issues/809\n" : ""}
|
|
3623
3623
|
|
|
3624
3624
|
## Project Structure
|
|
3625
3625
|
|
|
3626
3626
|
\`\`\`
|
|
3627
|
-
${projectName}
|
|
3628
|
-
├── apps/
|
|
3629
|
-
${hasTanstackRouter || hasReactRouter || hasNext || hasTanstackStart || hasSvelte || hasNuxt || hasSolid ? `│ ├── web/ # Frontend application (${hasTanstackRouter ? "React + TanStack Router" : hasReactRouter ? "React + React Router" : hasNext ? "Next.js" : hasTanstackStart ? "React + TanStack Start" : hasSvelte ? "SvelteKit" : hasNuxt ? "Nuxt" : hasSolid ? "SolidJS" : ""})\n` : ""}${hasNative ? "│ ├── native/ # Mobile application (React Native, Expo)\n" : ""}${addons.includes("starlight") ? "│ ├── docs/ # Documentation site (Astro Starlight)\n" : ""}${isConvex ? "├── packages/\n│ └── backend/ # Convex backend functions and schema\n" : `│ └── server/ # Backend API (${backend[0].toUpperCase() + backend.slice(1)}, ${api.toUpperCase()})`}
|
|
3627
|
+
${generateProjectStructure(projectName, frontend, backend, addons, isConvex, api)}
|
|
3630
3628
|
\`\`\`
|
|
3631
3629
|
|
|
3632
3630
|
## Available Scripts
|
|
@@ -3634,8 +3632,89 @@ ${hasTanstackRouter || hasReactRouter || hasNext || hasTanstackStart || hasSvelt
|
|
|
3634
3632
|
${generateScriptsList(packageManagerRunCmd, database, orm, auth, hasNative, addons, backend)}
|
|
3635
3633
|
`;
|
|
3636
3634
|
}
|
|
3635
|
+
function generateStackDescription(frontend, backend, api, isConvex) {
|
|
3636
|
+
const parts = [];
|
|
3637
|
+
const hasTanstackRouter = frontend.includes("tanstack-router");
|
|
3638
|
+
const hasReactRouter = frontend.includes("react-router");
|
|
3639
|
+
const hasNext = frontend.includes("next");
|
|
3640
|
+
const hasTanstackStart = frontend.includes("tanstack-start");
|
|
3641
|
+
const hasSvelte = frontend.includes("svelte");
|
|
3642
|
+
const hasNuxt = frontend.includes("nuxt");
|
|
3643
|
+
const hasSolid = frontend.includes("solid");
|
|
3644
|
+
const hasFrontendNone = frontend.length === 0 || frontend.includes("none");
|
|
3645
|
+
if (!hasFrontendNone) {
|
|
3646
|
+
if (hasTanstackRouter) parts.push("React, TanStack Router");
|
|
3647
|
+
else if (hasReactRouter) parts.push("React, React Router");
|
|
3648
|
+
else if (hasNext) parts.push("Next.js");
|
|
3649
|
+
else if (hasTanstackStart) parts.push("React, TanStack Start");
|
|
3650
|
+
else if (hasSvelte) parts.push("SvelteKit");
|
|
3651
|
+
else if (hasNuxt) parts.push("Nuxt");
|
|
3652
|
+
else if (hasSolid) parts.push("SolidJS");
|
|
3653
|
+
}
|
|
3654
|
+
if (backend !== "none") parts.push(backend[0].toUpperCase() + backend.slice(1));
|
|
3655
|
+
if (!isConvex && api !== "none") parts.push(api.toUpperCase());
|
|
3656
|
+
return parts.length > 0 ? `${parts.join(", ")}, and more` : "";
|
|
3657
|
+
}
|
|
3658
|
+
function generateRunningInstructions(frontend, backend, webPort, hasNative, isConvex) {
|
|
3659
|
+
const instructions = [];
|
|
3660
|
+
const hasFrontendNone = frontend.length === 0 || frontend.includes("none");
|
|
3661
|
+
const isBackendNone = backend === "none";
|
|
3662
|
+
if (!hasFrontendNone) {
|
|
3663
|
+
const hasTanstackRouter = frontend.includes("tanstack-router");
|
|
3664
|
+
const hasReactRouter = frontend.includes("react-router");
|
|
3665
|
+
const hasNext = frontend.includes("next");
|
|
3666
|
+
const hasTanstackStart = frontend.includes("tanstack-start");
|
|
3667
|
+
const hasSvelte = frontend.includes("svelte");
|
|
3668
|
+
const hasNuxt = frontend.includes("nuxt");
|
|
3669
|
+
const hasSolid = frontend.includes("solid");
|
|
3670
|
+
if (hasTanstackRouter || hasReactRouter || hasNext || hasTanstackStart || hasSvelte || hasNuxt || hasSolid) instructions.push(`Open [http://localhost:${webPort}](http://localhost:${webPort}) in your browser to see the web application.`);
|
|
3671
|
+
}
|
|
3672
|
+
if (hasNative) instructions.push("Use the Expo Go app to run the mobile application.");
|
|
3673
|
+
if (isConvex) instructions.push("Your app will connect to the Convex cloud backend automatically.");
|
|
3674
|
+
else if (!isBackendNone) instructions.push("The API is running at [http://localhost:3000](http://localhost:3000).");
|
|
3675
|
+
return instructions.join("\n");
|
|
3676
|
+
}
|
|
3677
|
+
function generateProjectStructure(projectName, frontend, backend, addons, isConvex, api) {
|
|
3678
|
+
const structure = [`${projectName}/`, "├── apps/"];
|
|
3679
|
+
const hasFrontendNone = frontend.length === 0 || frontend.includes("none");
|
|
3680
|
+
const isBackendNone = backend === "none";
|
|
3681
|
+
if (!hasFrontendNone) {
|
|
3682
|
+
const hasTanstackRouter = frontend.includes("tanstack-router");
|
|
3683
|
+
const hasReactRouter = frontend.includes("react-router");
|
|
3684
|
+
const hasNext = frontend.includes("next");
|
|
3685
|
+
const hasTanstackStart = frontend.includes("tanstack-start");
|
|
3686
|
+
const hasSvelte = frontend.includes("svelte");
|
|
3687
|
+
const hasNuxt = frontend.includes("nuxt");
|
|
3688
|
+
const hasSolid = frontend.includes("solid");
|
|
3689
|
+
if (hasTanstackRouter || hasReactRouter || hasNext || hasTanstackStart || hasSvelte || hasNuxt || hasSolid) {
|
|
3690
|
+
let frontendType = "";
|
|
3691
|
+
if (hasTanstackRouter) frontendType = "React + TanStack Router";
|
|
3692
|
+
else if (hasReactRouter) frontendType = "React + React Router";
|
|
3693
|
+
else if (hasNext) frontendType = "Next.js";
|
|
3694
|
+
else if (hasTanstackStart) frontendType = "React + TanStack Start";
|
|
3695
|
+
else if (hasSvelte) frontendType = "SvelteKit";
|
|
3696
|
+
else if (hasNuxt) frontendType = "Nuxt";
|
|
3697
|
+
else if (hasSolid) frontendType = "SolidJS";
|
|
3698
|
+
structure.push(`│ ├── web/ # Frontend application (${frontendType})`);
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
const hasNative = frontend.includes("native-nativewind") || frontend.includes("native-unistyles");
|
|
3702
|
+
if (hasNative) structure.push("│ ├── native/ # Mobile application (React Native, Expo)");
|
|
3703
|
+
if (addons.includes("starlight")) structure.push("│ ├── docs/ # Documentation site (Astro Starlight)");
|
|
3704
|
+
if (isConvex) {
|
|
3705
|
+
structure.push("├── packages/");
|
|
3706
|
+
structure.push("│ └── backend/ # Convex backend functions and schema");
|
|
3707
|
+
} else if (!isBackendNone) {
|
|
3708
|
+
const backendName = backend[0].toUpperCase() + backend.slice(1);
|
|
3709
|
+
const apiName = api !== "none" ? api.toUpperCase() : "";
|
|
3710
|
+
const backendDesc = apiName ? `${backendName}, ${apiName}` : backendName;
|
|
3711
|
+
structure.push(`│ └── server/ # Backend API (${backendDesc})`);
|
|
3712
|
+
}
|
|
3713
|
+
return structure.join("\n");
|
|
3714
|
+
}
|
|
3637
3715
|
function generateFeaturesList(database, auth, addons, orm, runtime, frontend, backend, api) {
|
|
3638
3716
|
const isConvex = backend === "convex";
|
|
3717
|
+
const isBackendNone = backend === "none";
|
|
3639
3718
|
const hasTanstackRouter = frontend.includes("tanstack-router");
|
|
3640
3719
|
const hasReactRouter = frontend.includes("react-router");
|
|
3641
3720
|
const hasNative = frontend.includes("native-nativewind") || frontend.includes("native-unistyles");
|
|
@@ -3644,21 +3723,24 @@ function generateFeaturesList(database, auth, addons, orm, runtime, frontend, ba
|
|
|
3644
3723
|
const hasSvelte = frontend.includes("svelte");
|
|
3645
3724
|
const hasNuxt = frontend.includes("nuxt");
|
|
3646
3725
|
const hasSolid = frontend.includes("solid");
|
|
3726
|
+
const hasFrontendNone = frontend.length === 0 || frontend.includes("none");
|
|
3647
3727
|
const addonsList = ["- **TypeScript** - For type safety and improved developer experience"];
|
|
3648
|
-
if (
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3728
|
+
if (!hasFrontendNone) {
|
|
3729
|
+
if (hasTanstackRouter) addonsList.push("- **TanStack Router** - File-based routing with full type safety");
|
|
3730
|
+
else if (hasReactRouter) addonsList.push("- **React Router** - Declarative routing for React");
|
|
3731
|
+
else if (hasNext) addonsList.push("- **Next.js** - Full-stack React framework");
|
|
3732
|
+
else if (hasTanstackStart) addonsList.push("- **TanStack Start** - SSR framework with TanStack Router");
|
|
3733
|
+
else if (hasSvelte) addonsList.push("- **SvelteKit** - Web framework for building Svelte apps");
|
|
3734
|
+
else if (hasNuxt) addonsList.push("- **Nuxt** - The Intuitive Vue Framework");
|
|
3735
|
+
else if (hasSolid) addonsList.push("- **SolidJS** - Simple and performant reactivity");
|
|
3736
|
+
}
|
|
3655
3737
|
if (hasNative) {
|
|
3656
3738
|
addonsList.push("- **React Native** - Build mobile apps using React");
|
|
3657
3739
|
addonsList.push("- **Expo** - Tools for React Native development");
|
|
3658
3740
|
}
|
|
3659
|
-
addonsList.push("- **TailwindCSS** - Utility-first CSS for rapid UI development", "- **shadcn/ui** - Reusable UI components");
|
|
3741
|
+
if (!hasFrontendNone) addonsList.push("- **TailwindCSS** - Utility-first CSS for rapid UI development", "- **shadcn/ui** - Reusable UI components");
|
|
3660
3742
|
if (isConvex) addonsList.push("- **Convex** - Reactive backend-as-a-service platform");
|
|
3661
|
-
else {
|
|
3743
|
+
else if (!isBackendNone) {
|
|
3662
3744
|
if (backend === "hono") addonsList.push("- **Hono** - Lightweight, performant server framework");
|
|
3663
3745
|
else if (backend === "express") addonsList.push("- **Express** - Fast, unopinionated web framework");
|
|
3664
3746
|
else if (backend === "fastify") addonsList.push("- **Fastify** - Fast, low-overhead web framework");
|
|
@@ -3666,9 +3748,13 @@ function generateFeaturesList(database, auth, addons, orm, runtime, frontend, ba
|
|
|
3666
3748
|
else if (backend === "next") addonsList.push("- **Next.js** - Full-stack React framework");
|
|
3667
3749
|
if (api === "trpc") addonsList.push("- **tRPC** - End-to-end type-safe APIs");
|
|
3668
3750
|
else if (api === "orpc") addonsList.push("- **oRPC** - End-to-end type-safe APIs with OpenAPI integration");
|
|
3669
|
-
addonsList.push(`- **${runtime === "bun" ? "Bun" : "Node.js"}** - Runtime environment`);
|
|
3751
|
+
if (runtime !== "none") addonsList.push(`- **${runtime === "bun" ? "Bun" : runtime === "node" ? "Node.js" : runtime}** - Runtime environment`);
|
|
3752
|
+
}
|
|
3753
|
+
if (database !== "none" && !isConvex) {
|
|
3754
|
+
const ormName = orm === "drizzle" ? "Drizzle" : orm === "prisma" ? "Prisma" : orm === "mongoose" ? "Mongoose" : "ORM";
|
|
3755
|
+
const dbName = database === "sqlite" ? "SQLite/Turso" : database === "postgres" ? "PostgreSQL" : database === "mysql" ? "MySQL" : database === "mongodb" ? "MongoDB" : "Database";
|
|
3756
|
+
addonsList.push(`- **${ormName}** - TypeScript-first ORM`, `- **${dbName}** - Database engine`);
|
|
3670
3757
|
}
|
|
3671
|
-
if (database !== "none" && !isConvex) addonsList.push(`- **${orm === "drizzle" ? "Drizzle" : orm === "prisma" ? "Prisma" : "Mongoose"}** - TypeScript-first ORM`, `- **${database === "sqlite" ? "SQLite/Turso" : database === "postgres" ? "PostgreSQL" : database === "mysql" ? "MySQL" : "MongoDB"}** - Database engine`);
|
|
3672
3758
|
if (auth && !isConvex) addonsList.push("- **Authentication** - Email & password authentication with Better Auth");
|
|
3673
3759
|
for (const addon of addons) if (addon === "pwa") addonsList.push("- **PWA** - Progressive Web App support");
|
|
3674
3760
|
else if (addon === "tauri") addonsList.push("- **Tauri** - Build native desktop applications");
|
|
@@ -3678,10 +3764,10 @@ function generateFeaturesList(database, auth, addons, orm, runtime, frontend, ba
|
|
|
3678
3764
|
else if (addon === "turborepo") addonsList.push("- **Turborepo** - Optimized monorepo build system");
|
|
3679
3765
|
return addonsList.join("\n");
|
|
3680
3766
|
}
|
|
3681
|
-
function generateDatabaseSetup(database,
|
|
3767
|
+
function generateDatabaseSetup(database, _auth, packageManagerRunCmd, orm) {
|
|
3682
3768
|
if (database === "none") return "";
|
|
3683
3769
|
let setup = "## Database Setup\n\n";
|
|
3684
|
-
if (database === "sqlite") setup += `This project uses SQLite${orm === "drizzle" ? " with Drizzle ORM" : " with Prisma"}.
|
|
3770
|
+
if (database === "sqlite") setup += `This project uses SQLite${orm === "drizzle" ? " with Drizzle ORM" : orm === "prisma" ? " with Prisma" : ` with ${orm}`}.
|
|
3685
3771
|
|
|
3686
3772
|
1. Start the local SQLite database:
|
|
3687
3773
|
\`\`\`bash
|
|
@@ -3690,23 +3776,23 @@ cd apps/server && ${packageManagerRunCmd} db:local
|
|
|
3690
3776
|
|
|
3691
3777
|
2. Update your \`.env\` file in the \`apps/server\` directory with the appropriate connection details if needed.
|
|
3692
3778
|
`;
|
|
3693
|
-
else if (database === "postgres") setup += `This project uses PostgreSQL${orm === "drizzle" ? " with Drizzle ORM" : " with Prisma"}.
|
|
3779
|
+
else if (database === "postgres") setup += `This project uses PostgreSQL${orm === "drizzle" ? " with Drizzle ORM" : orm === "prisma" ? " with Prisma" : ` with ${orm}`}.
|
|
3694
3780
|
|
|
3695
3781
|
1. Make sure you have a PostgreSQL database set up.
|
|
3696
3782
|
2. Update your \`apps/server/.env\` file with your PostgreSQL connection details.
|
|
3697
3783
|
`;
|
|
3698
|
-
else if (database === "mysql") setup += `This project uses MySQL${orm === "drizzle" ? " with Drizzle ORM" : " with Prisma"}.
|
|
3784
|
+
else if (database === "mysql") setup += `This project uses MySQL${orm === "drizzle" ? " with Drizzle ORM" : orm === "prisma" ? " with Prisma" : ` with ${orm}`}.
|
|
3699
3785
|
|
|
3700
3786
|
1. Make sure you have a MySQL database set up.
|
|
3701
3787
|
2. Update your \`apps/server/.env\` file with your MySQL connection details.
|
|
3702
3788
|
`;
|
|
3703
|
-
else if (database === "mongodb") setup += `This project uses MongoDB ${orm === "mongoose" ? "with Mongoose" : "with Prisma ORM"}.
|
|
3789
|
+
else if (database === "mongodb") setup += `This project uses MongoDB ${orm === "mongoose" ? "with Mongoose" : orm === "prisma" ? "with Prisma ORM" : `with ${orm}`}.
|
|
3704
3790
|
|
|
3705
3791
|
1. Make sure you have MongoDB set up.
|
|
3706
3792
|
2. Update your \`apps/server/.env\` file with your MongoDB connection URI.
|
|
3707
3793
|
`;
|
|
3708
3794
|
setup += `
|
|
3709
|
-
|
|
3795
|
+
3. ${orm === "prisma" ? `Generate the Prisma client and push the schema:
|
|
3710
3796
|
\`\`\`bash
|
|
3711
3797
|
${packageManagerRunCmd} db:push
|
|
3712
3798
|
\`\`\`` : orm === "drizzle" ? `Apply the schema to your database:
|
|
@@ -3721,12 +3807,14 @@ ${packageManagerRunCmd} db:push
|
|
|
3721
3807
|
}
|
|
3722
3808
|
function generateScriptsList(packageManagerRunCmd, database, orm, _auth, hasNative, addons, backend) {
|
|
3723
3809
|
const isConvex = backend === "convex";
|
|
3810
|
+
const isBackendNone = backend === "none";
|
|
3724
3811
|
let scripts = `- \`${packageManagerRunCmd} dev\`: Start all applications in development mode
|
|
3725
|
-
- \`${packageManagerRunCmd} build\`: Build all applications
|
|
3812
|
+
- \`${packageManagerRunCmd} build\`: Build all applications`;
|
|
3813
|
+
scripts += `
|
|
3726
3814
|
- \`${packageManagerRunCmd} dev:web\`: Start only the web application`;
|
|
3727
3815
|
if (isConvex) scripts += `
|
|
3728
3816
|
- \`${packageManagerRunCmd} dev:setup\`: Setup and configure your Convex project`;
|
|
3729
|
-
else scripts += `
|
|
3817
|
+
else if (!isBackendNone) scripts += `
|
|
3730
3818
|
- \`${packageManagerRunCmd} dev:server\`: Start only the server`;
|
|
3731
3819
|
scripts += `
|
|
3732
3820
|
- \`${packageManagerRunCmd} check-types\`: Check TypeScript types across all apps`;
|
|
@@ -3787,6 +3875,7 @@ function displayPostInstallInstructions(config) {
|
|
|
3787
3875
|
if (!depsInstalled) output += `${pc.cyan(`${stepCounter++}.`)} ${packageManager} install\n`;
|
|
3788
3876
|
if (isConvex) {
|
|
3789
3877
|
output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev:setup ${pc.dim("(this will guide you through Convex project setup)")}\n`;
|
|
3878
|
+
output += `${pc.cyan(`${stepCounter++}.`)} Copy environment variables from ${pc.white("packages/backend/.env.local")} \nto ${pc.white("apps/*/.env")}\n`;
|
|
3790
3879
|
output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev\n\n`;
|
|
3791
3880
|
} else {
|
|
3792
3881
|
if (runtime !== "workers") output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev\n`;
|
|
@@ -3898,7 +3987,7 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
3898
3987
|
scripts["dev:native"] = "turbo -F native dev";
|
|
3899
3988
|
scripts["dev:web"] = "turbo -F web dev";
|
|
3900
3989
|
scripts["dev:server"] = serverDevScript;
|
|
3901
|
-
if (options.backend === "convex") scripts["dev:setup"] = `turbo -F ${backendPackageName} setup`;
|
|
3990
|
+
if (options.backend === "convex") scripts["dev:setup"] = `turbo -F ${backendPackageName} dev:setup`;
|
|
3902
3991
|
if (needsDbScripts) {
|
|
3903
3992
|
scripts["db:push"] = `turbo -F ${backendPackageName} db:push`;
|
|
3904
3993
|
scripts["db:studio"] = `turbo -F ${backendPackageName} db:studio`;
|
|
@@ -3917,7 +4006,7 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
3917
4006
|
scripts["dev:native"] = "pnpm --filter native dev";
|
|
3918
4007
|
scripts["dev:web"] = "pnpm --filter web dev";
|
|
3919
4008
|
scripts["dev:server"] = serverDevScript;
|
|
3920
|
-
if (options.backend === "convex") scripts["dev:setup"] = `pnpm --filter ${backendPackageName} setup`;
|
|
4009
|
+
if (options.backend === "convex") scripts["dev:setup"] = `pnpm --filter ${backendPackageName} dev:setup`;
|
|
3921
4010
|
if (needsDbScripts) {
|
|
3922
4011
|
scripts["db:push"] = `pnpm --filter ${backendPackageName} db:push`;
|
|
3923
4012
|
scripts["db:studio"] = `pnpm --filter ${backendPackageName} db:studio`;
|
|
@@ -3936,7 +4025,7 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
3936
4025
|
scripts["dev:native"] = "npm run dev --workspace native";
|
|
3937
4026
|
scripts["dev:web"] = "npm run dev --workspace web";
|
|
3938
4027
|
scripts["dev:server"] = serverDevScript;
|
|
3939
|
-
if (options.backend === "convex") scripts["dev:setup"] = `npm run setup --workspace ${backendPackageName}`;
|
|
4028
|
+
if (options.backend === "convex") scripts["dev:setup"] = `npm run dev:setup --workspace ${backendPackageName}`;
|
|
3940
4029
|
if (needsDbScripts) {
|
|
3941
4030
|
scripts["db:push"] = `npm run db:push --workspace ${backendPackageName}`;
|
|
3942
4031
|
scripts["db:studio"] = `npm run db:studio --workspace ${backendPackageName}`;
|
|
@@ -3955,7 +4044,7 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
3955
4044
|
scripts["dev:native"] = "bun run --filter native dev";
|
|
3956
4045
|
scripts["dev:web"] = "bun run --filter web dev";
|
|
3957
4046
|
scripts["dev:server"] = serverDevScript;
|
|
3958
|
-
if (options.backend === "convex") scripts["dev:setup"] = `bun run --filter ${backendPackageName} setup`;
|
|
4047
|
+
if (options.backend === "convex") scripts["dev:setup"] = `bun run --filter ${backendPackageName} dev:setup`;
|
|
3959
4048
|
if (needsDbScripts) {
|
|
3960
4049
|
scripts["db:push"] = `bun run --filter ${backendPackageName} db:push`;
|
|
3961
4050
|
scripts["db:studio"] = `bun run --filter ${backendPackageName} db:studio`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-better-t-stack",
|
|
3
|
-
"version": "2.22.
|
|
3
|
+
"version": "2.22.6",
|
|
4
4
|
"description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "convex dev",
|
|
6
|
-
"setup": "convex dev --configure --until-success"
|
|
6
|
+
"dev:setup": "convex dev --configure --until-success"
|
|
7
7
|
},
|
|
8
8
|
"author": "",
|
|
9
9
|
"license": "ISC",
|
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
"typescript": "^5.8.3"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"convex": "^1.
|
|
15
|
+
"convex": "^1.25.0"
|
|
16
16
|
}
|
|
17
17
|
}
|
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
{{#if (or (eq runtime "bun") (eq runtime "node"))}}
|
|
2
|
+
{{#if (eq dbSetup "neon")}}
|
|
3
|
+
import { neon } from '@neondatabase/serverless';
|
|
4
|
+
import { drizzle } from 'drizzle-orm/neon-http';
|
|
5
|
+
|
|
6
|
+
const sql = neon(process.env.DATABASE_URL || "");
|
|
7
|
+
export const db = drizzle(sql);
|
|
8
|
+
{{else}}
|
|
2
9
|
import { drizzle } from "drizzle-orm/node-postgres";
|
|
3
10
|
|
|
4
11
|
export const db = drizzle(process.env.DATABASE_URL || "");
|
|
5
12
|
{{/if}}
|
|
13
|
+
{{/if}}
|
|
6
14
|
|
|
7
15
|
{{#if (eq runtime "workers")}}
|
|
16
|
+
{{#if (eq dbSetup "neon")}}
|
|
17
|
+
import { neon } from '@neondatabase/serverless';
|
|
18
|
+
import { drizzle } from 'drizzle-orm/neon-http';
|
|
19
|
+
import { env } from "cloudflare:workers";
|
|
20
|
+
|
|
21
|
+
const sql = neon(env.DATABASE_URL || "");
|
|
22
|
+
export const db = drizzle(sql);
|
|
23
|
+
{{else}}
|
|
8
24
|
import { drizzle } from "drizzle-orm/node-postgres";
|
|
9
25
|
import { env } from "cloudflare:workers";
|
|
10
26
|
|
|
11
27
|
export const db = drizzle(env.DATABASE_URL || "");
|
|
12
28
|
{{/if}}
|
|
29
|
+
{{/if}}
|