diff --git a/README.md b/README.md
index 68c6c25b..01480783 100644
--- a/README.md
+++ b/README.md
@@ -10,48 +10,58 @@ A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with

+## Philosophy
+
+- Roll your own stack: you pick only the parts you need, nothing extra.
+- Minimal templates: bare-bones scaffolds with zero bloat.
+- Latest dependencies: always use current, stable versions by default.
+- Free and open source: forever.
+
## Quick Start
```bash
-# Using npm
-npx create-better-t-stack@latest
-
-# Using bun
+# Using bun (recommended)
bun create better-t-stack@latest
# Using pnpm
pnpm create better-t-stack@latest
+
+# Using npm
+npx create-better-t-stack@latest
```
## Features
-- **Zero-config setup** with interactive CLI wizard
-- **End-to-end type safety** from database to frontend via tRPC
-- **Modern stack** with React, Hono/Elysia, and TanStack libraries
-- **Multi-platform** supporting web, mobile (Expo), and desktop applications
-- **Database flexibility** with SQLite (Turso) or PostgreSQL options
-- **ORM choice** between Drizzle or Prisma
-- **Built-in authentication** with Better-Auth
-- **Optional PWA support** for installable web applications
-- **Desktop app capabilities** with Tauri integration
-- **Monorepo architecture** powered by Turborepo
+- Frontend: React (TanStack Router, React Router, TanStack Start), Next.js, Nuxt, Svelte, Solid, React Native (NativeWind/Unistyles), or none
+- Backend: Hono, Express, Fastify, Elysia, Next API Routes, Convex, or none
+- API: tRPC or oRPC (or none)
+- Runtime: Bun, Node.js, or Cloudflare Workers
+- Databases: SQLite, PostgreSQL, MySQL, MongoDB (or none)
+- ORMs: Drizzle, Prisma, Mongoose (or none)
+- Auth: Better-Auth (optional)
+- Addons: Turborepo, PWA, Tauri, Biome, Husky, Starlight, Fumadocs, Ultracite, Oxlint
+- Examples: Todo, AI
+- DB Setup: Turso, Neon, Supabase, Prisma PostgreSQL, MongoDB Atlas, Cloudflare D1, Docker
+- Web Deploy: Cloudflare Workers
+
+Type safety end-to-end, clean monorepo layout, and zero lock-in: you choose only what you need.
## Repository Structure
This repository is organized as a monorepo containing:
-- **CLI**: [`create-better-t-stack`](apps/cli) - The scaffolding CLI tool
-- **Documentation**: [`web`](apps/web) - Official website and documentation
+- **CLI**: [`apps/cli`](apps/cli) - The scaffolding CLI tool
+- **Documentation**: [`apps/web`](apps/web) - Official website and documentation
## Documentation
-Visit [better-t-stack.dev](https://better-t-stack.dev) for full documentation, guides, and examples.
+Visit [better-t-stack.dev](https://better-t-stack.dev) for full documentation, guides, and examples. You can also use the visual Stack Builder at `https://better-t-stack.dev/new` to generate a command for your stack.
## Development
```bash
# Clone the repository
-git clone https://github.com/better-t-stack/create-better-t-stack.git
+git clone https://github.com/AmanVarshney01/create-better-t-stack.git
# Install dependencies
bun install
@@ -65,7 +75,10 @@ bun dev:web
## Want to contribute?
-Just fork the repository and submit a pull request!
+Please read the Contribution Guide first and open an issue before starting new features to ensure alignment with project goals.
+
+- Docs: [`Contributing`](/apps/web/content/docs/contributing.mdx)
+- Repo guide: [`.github/CONTRIBUTING.md`](.github/CONTRIBUTING.md)
## Star History
diff --git a/apps/cli/README.md b/apps/cli/README.md
index 94e541e4..419039be 100644
--- a/apps/cli/README.md
+++ b/apps/cli/README.md
@@ -15,14 +15,14 @@ A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with
Run without installing globally:
```bash
-# Using npm
-npx create-better-t-stack@latest
-
-# Using bun
+# Using bun (recommended)
bun create better-t-stack@latest
# Using pnpm
pnpm create better-t-stack@latest
+
+# Using npm
+npx create-better-t-stack@latest
```
Follow the prompts to configure your project or use the `--yes` flag for defaults.
@@ -58,14 +58,15 @@ Options:
--auth Include authentication
--no-auth Exclude authentication
--frontend Frontend types (tanstack-router, react-router, tanstack-start, next, nuxt, svelte, solid, native-nativewind, native-unistyles, none)
- --addons Additional addons (pwa, tauri, starlight, biome, husky, turborepo, none)
+ --addons Additional addons (pwa, tauri, starlight, biome, husky, turborepo, fumadocs, ultracite, oxlint, none)
--examples Examples to include (todo, ai, none)
--git Initialize git repository
--no-git Skip git initialization
--package-manager Package manager (npm, pnpm, bun)
--install Install dependencies
--no-install Skip installing dependencies
- --db-setup Database setup (turso, d1, neon, supabase, prisma-postgres, mongodb-atlas, none)
+ --db-setup Database setup (turso, d1, neon, supabase, prisma-postgres, mongodb-atlas, docker, none)
+ --web-deploy Web deployment (workers, none)
--backend Backend framework (hono, express, elysia, next, convex, fastify, none)
--runtime Runtime (bun, node, workers, none)
--api API type (trpc, orpc, none)
@@ -84,7 +85,7 @@ This CLI collects anonymous usage data to help improve the tool. The data collec
### Disabling Telemetry
-You can disable telemetry by setting the `BTS_TELEMETRY` environment variable:
+You can disable telemetry by setting the `BTS_TELEMETRY_DISABLED` environment variable:
```bash
# Disable telemetry for a single run
@@ -94,10 +95,6 @@ BTS_TELEMETRY_DISABLED=1 npx create-better-t-stack my-app
export BTS_TELEMETRY_DISABLED=1
```
-### Development
-
-During development, telemetry is automatically disabled when `NODE_ENV=development`.
-
## Examples
Create a project with default configuration:
@@ -118,10 +115,10 @@ Create a project with Elysia backend and Node.js runtime:
npx create-better-t-stack my-app --backend elysia --runtime node
```
-Create a project with multiple frontend options:
+Create a project with multiple frontend options (one web + one native):
```bash
-npx create-better-t-stack my-app --frontend tanstack-router native
+npx create-better-t-stack my-app --frontend tanstack-router native-nativewind
```
Create a project with examples:
diff --git a/apps/cli/src/constants.ts b/apps/cli/src/constants.ts
index cdd55111..2130559c 100644
--- a/apps/cli/src/constants.ts
+++ b/apps/cli/src/constants.ts
@@ -139,14 +139,3 @@ export const ADDON_COMPATIBILITY: Record = {
fumadocs: [],
none: [],
} as const;
-
-// TODO: need to refactor this
-export const WEB_FRAMEWORKS: readonly Frontend[] = [
- "tanstack-router",
- "react-router",
- "tanstack-start",
- "next",
- "nuxt",
- "svelte",
- "solid",
-];
diff --git a/apps/cli/src/prompts/api.ts b/apps/cli/src/prompts/api.ts
index 48d12b3b..26b0c780 100644
--- a/apps/cli/src/prompts/api.ts
+++ b/apps/cli/src/prompts/api.ts
@@ -1,6 +1,7 @@
import { cancel, isCancel, select } from "@clack/prompts";
import pc from "picocolors";
import type { API, Backend, Frontend } from "../types";
+import { allowedApisForFrontends } from "../utils/compatibility-rules";
export async function getApiChoice(
Api?: API | undefined,
@@ -11,46 +12,30 @@ export async function getApiChoice(
return "none";
}
- if (Api) return Api;
+ const allowed = allowedApisForFrontends(frontend ?? []);
- const includesNuxt = frontend?.includes("nuxt");
- const includesSvelte = frontend?.includes("svelte");
- const includesSolid = frontend?.includes("solid");
-
- let apiOptions = [
- {
- value: "trpc" as const,
- label: "tRPC",
- hint: "End-to-end typesafe APIs made easy",
- },
- {
- value: "orpc" as const,
- label: "oRPC",
- hint: "End-to-end type-safe APIs that adhere to OpenAPI standards",
- },
- {
- value: "none" as const,
- label: "None",
- hint: "No API layer (e.g. for full-stack frameworks like Next.js with Route Handlers)",
- },
- ];
-
- if (includesNuxt || includesSvelte || includesSolid) {
- apiOptions = [
- {
- value: "orpc" as const,
- label: "oRPC",
- hint: `End-to-end type-safe APIs (Recommended for ${
- includesNuxt ? "Nuxt" : includesSvelte ? "Svelte" : "Solid"
- } frontend)`,
- },
- {
- value: "none" as const,
- label: "None",
- hint: "No API layer",
- },
- ];
+ if (Api) {
+ return allowed.includes(Api) ? Api : allowed[0];
}
+ const apiOptions = allowed.map((a) =>
+ a === "trpc"
+ ? {
+ value: "trpc" as const,
+ label: "tRPC",
+ hint: "End-to-end typesafe APIs made easy",
+ }
+ : a === "orpc"
+ ? {
+ value: "orpc" as const,
+ label: "oRPC",
+ hint: "End-to-end type-safe APIs that adhere to OpenAPI standards",
+ }
+ : {
+ value: "none" as const,
+ label: "None",
+ hint: "No API layer (e.g. for full-stack frameworks like Next.js with Route Handlers)",
+ },
+ );
const apiType = await select({
message: "Select API type",
diff --git a/apps/cli/src/prompts/examples.ts b/apps/cli/src/prompts/examples.ts
index 3d39ada8..13244edc 100644
--- a/apps/cli/src/prompts/examples.ts
+++ b/apps/cli/src/prompts/examples.ts
@@ -2,6 +2,10 @@ import { cancel, isCancel, multiselect } from "@clack/prompts";
import pc from "picocolors";
import { DEFAULT_CONFIG } from "../constants";
import type { API, Backend, Database, Examples, Frontend } from "../types";
+import {
+ isExampleAIAllowed,
+ isExampleTodoAllowed,
+} from "../utils/compatibility-rules";
export async function getExamplesChoice(
examples?: Examples[],
@@ -30,15 +34,17 @@ export async function getExamplesChoice(
if (noFrontendSelected) return [];
let response: Examples[] | symbol = [];
- const options: { value: Examples; label: string; hint: string }[] = [
- {
+ const options: { value: Examples; label: string; hint: string }[] = [];
+
+ if (isExampleTodoAllowed(backend, database)) {
+ options.push({
value: "todo" as const,
label: "Todo App",
hint: "A simple CRUD example app",
- },
- ];
+ });
+ }
- if (backend !== "elysia" && !frontends?.includes("solid")) {
+ if (isExampleAIAllowed(backend, frontends ?? [])) {
options.push({
value: "ai" as const,
label: "AI Chat",
@@ -46,11 +52,15 @@ export async function getExamplesChoice(
});
}
+ if (options.length === 0) return [];
+
response = await multiselect({
message: "Include examples",
options: options,
required: false,
- initialValues: DEFAULT_CONFIG.examples,
+ initialValues: DEFAULT_CONFIG.examples?.filter((ex) =>
+ options.some((o) => o.value === ex),
+ ),
});
if (isCancel(response)) {
diff --git a/apps/cli/src/prompts/frontend.ts b/apps/cli/src/prompts/frontend.ts
index e4eb9c08..c337ada0 100644
--- a/apps/cli/src/prompts/frontend.ts
+++ b/apps/cli/src/prompts/frontend.ts
@@ -2,6 +2,7 @@ import { cancel, isCancel, multiselect, select } from "@clack/prompts";
import pc from "picocolors";
import { DEFAULT_CONFIG } from "../constants";
import type { Backend, Frontend } from "../types";
+import { isFrontendAllowedWithBackend } from "../utils/compatibility-rules";
export async function getFrontendChoice(
frontendOptions?: Frontend[],
@@ -73,12 +74,9 @@ export async function getFrontendChoice(
},
];
- const webOptions = allWebOptions.filter((option) => {
- if (backend === "convex") {
- return option.value !== "solid";
- }
- return true;
- });
+ const webOptions = allWebOptions.filter((option) =>
+ isFrontendAllowedWithBackend(option.value, backend),
+ );
const webFramework = await select({
message: "Choose web",
diff --git a/apps/cli/src/prompts/project-name.ts b/apps/cli/src/prompts/project-name.ts
index 0b5be852..762a163a 100644
--- a/apps/cli/src/prompts/project-name.ts
+++ b/apps/cli/src/prompts/project-name.ts
@@ -1,10 +1,17 @@
import path from "node:path";
import { cancel, isCancel, text } from "@clack/prompts";
+import consola from "consola";
import fs from "fs-extra";
import pc from "picocolors";
import { DEFAULT_CONFIG } from "../constants";
import { ProjectNameSchema } from "../types";
+function isPathWithinCwd(targetPath: string): boolean {
+ const resolved = path.resolve(targetPath);
+ const rel = path.relative(process.cwd(), resolved);
+ return !rel.startsWith("..") && !path.isAbsolute(rel);
+}
+
function validateDirectoryName(name: string): string | undefined {
if (name === ".") return undefined;
@@ -23,7 +30,11 @@ export async function getProjectName(initialName?: string): Promise {
const finalDirName = path.basename(initialName);
const validationError = validateDirectoryName(finalDirName);
if (!validationError) {
- return initialName;
+ const projectDir = path.resolve(process.cwd(), initialName);
+ if (isPathWithinCwd(projectDir)) {
+ return initialName;
+ }
+ consola.error(pc.red("Project path must be within current directory"));
}
}
@@ -56,7 +67,7 @@ export async function getProjectName(initialName?: string): Promise {
if (nameToUse !== ".") {
const projectDir = path.resolve(process.cwd(), nameToUse);
- if (!projectDir.startsWith(process.cwd())) {
+ if (!isPathWithinCwd(projectDir)) {
return "Project path must be within current directory";
}
}
diff --git a/apps/cli/src/prompts/web-deploy.ts b/apps/cli/src/prompts/web-deploy.ts
index 8622556f..e948758a 100644
--- a/apps/cli/src/prompts/web-deploy.ts
+++ b/apps/cli/src/prompts/web-deploy.ts
@@ -1,7 +1,8 @@
import { cancel, isCancel, select } from "@clack/prompts";
import pc from "picocolors";
-import { DEFAULT_CONFIG, WEB_FRAMEWORKS } from "../constants";
+import { DEFAULT_CONFIG } from "../constants";
import type { Backend, Frontend, Runtime, WebDeploy } from "../types";
+import { WEB_FRAMEWORKS } from "../utils/compatibility";
function hasWebFrontend(frontends: Frontend[]): boolean {
return frontends.some((f) => WEB_FRAMEWORKS.includes(f));
diff --git a/apps/cli/src/types.ts b/apps/cli/src/types.ts
index 536a1748..4997ceb4 100644
--- a/apps/cli/src/types.ts
+++ b/apps/cli/src/types.ts
@@ -17,9 +17,7 @@ export type Backend = z.infer;
export const RuntimeSchema = z
.enum(["bun", "node", "workers", "none"])
- .describe(
- "Runtime environment (workers only available with hono backend and drizzle orm)",
- );
+ .describe("Runtime environment");
export type Runtime = z.infer;
export const FrontendSchema = z
@@ -176,5 +174,3 @@ export interface BetterTStackConfig {
api: API;
webDeploy: WebDeploy;
}
-
-export type AvailablePackageManagers = "npm" | "pnpm" | "bun";
diff --git a/apps/cli/src/utils/compatibility-rules.ts b/apps/cli/src/utils/compatibility-rules.ts
new file mode 100644
index 00000000..637abdca
--- /dev/null
+++ b/apps/cli/src/utils/compatibility-rules.ts
@@ -0,0 +1,315 @@
+import { consola } from "consola";
+import type {
+ Addons,
+ API,
+ CLIInput,
+ Frontend,
+ ProjectConfig,
+ WebDeploy,
+} from "../types";
+import { validateAddonCompatibility } from "./addon-compatibility";
+import { WEB_FRAMEWORKS } from "./compatibility";
+
+export function isWebFrontend(value: Frontend): boolean {
+ return WEB_FRAMEWORKS.includes(value);
+}
+
+export function splitFrontends(values: Frontend[] = []): {
+ web: Frontend[];
+ native: Frontend[];
+} {
+ const web = values.filter((f) => isWebFrontend(f));
+ const native = values.filter(
+ (f) => f === "native-nativewind" || f === "native-unistyles",
+ );
+ return { web, native };
+}
+
+export function ensureSingleWebAndNative(frontends: Frontend[]) {
+ const { web, native } = splitFrontends(frontends);
+ if (web.length > 1) {
+ consola.fatal(
+ "Cannot select multiple web frameworks. Choose only one of: tanstack-router, tanstack-start, react-router, next, nuxt, svelte, solid",
+ );
+ process.exit(1);
+ }
+ if (native.length > 1) {
+ consola.fatal(
+ "Cannot select multiple native frameworks. Choose only one of: native-nativewind, native-unistyles",
+ );
+ process.exit(1);
+ }
+}
+
+export function validateWorkersCompatibility(
+ providedFlags: Set,
+ options: CLIInput,
+ config: Partial,
+) {
+ if (
+ providedFlags.has("runtime") &&
+ options.runtime === "workers" &&
+ config.backend &&
+ config.backend !== "hono"
+ ) {
+ consola.fatal(
+ `Cloudflare Workers runtime (--runtime workers) is only supported with Hono backend (--backend hono). Current backend: ${config.backend}. Please use '--backend hono' or choose a different runtime.`,
+ );
+ process.exit(1);
+ }
+
+ if (
+ providedFlags.has("backend") &&
+ config.backend &&
+ config.backend !== "hono" &&
+ config.runtime === "workers"
+ ) {
+ consola.fatal(
+ `Backend '${config.backend}' is not compatible with Cloudflare Workers runtime. Cloudflare Workers runtime is only supported with Hono backend. Please use '--backend hono' or choose a different runtime.`,
+ );
+ process.exit(1);
+ }
+
+ if (
+ providedFlags.has("runtime") &&
+ options.runtime === "workers" &&
+ config.orm &&
+ config.orm !== "drizzle" &&
+ config.orm !== "none"
+ ) {
+ consola.fatal(
+ `Cloudflare Workers runtime (--runtime workers) is only supported with Drizzle ORM (--orm drizzle) or no ORM (--orm none). Current ORM: ${config.orm}. Please use '--orm drizzle', '--orm none', or choose a different runtime.`,
+ );
+ process.exit(1);
+ }
+
+ if (
+ providedFlags.has("orm") &&
+ config.orm &&
+ config.orm !== "drizzle" &&
+ config.orm !== "none" &&
+ config.runtime === "workers"
+ ) {
+ consola.fatal(
+ `ORM '${config.orm}' is not compatible with Cloudflare Workers runtime. Cloudflare Workers runtime is only supported with Drizzle ORM or no ORM. Please use '--orm drizzle', '--orm none', or choose a different runtime.`,
+ );
+ process.exit(1);
+ }
+
+ if (
+ providedFlags.has("runtime") &&
+ options.runtime === "workers" &&
+ config.database === "mongodb"
+ ) {
+ consola.fatal(
+ "Cloudflare Workers runtime (--runtime workers) is not compatible with MongoDB database. MongoDB requires Prisma or Mongoose ORM, but Workers runtime only supports Drizzle ORM. Please use a different database or runtime.",
+ );
+ process.exit(1);
+ }
+
+ if (
+ providedFlags.has("runtime") &&
+ options.runtime === "workers" &&
+ config.dbSetup === "docker"
+ ) {
+ consola.fatal(
+ "Cloudflare Workers runtime (--runtime workers) is not compatible with Docker setup. Workers runtime uses serverless databases (D1) and doesn't support local Docker containers. Please use '--db-setup d1' for SQLite or choose a different runtime.",
+ );
+ process.exit(1);
+ }
+
+ if (
+ providedFlags.has("database") &&
+ config.database === "mongodb" &&
+ config.runtime === "workers"
+ ) {
+ consola.fatal(
+ "MongoDB database is not compatible with Cloudflare Workers runtime. MongoDB requires Prisma or Mongoose ORM, but Workers runtime only supports Drizzle ORM. Please use a different database or runtime.",
+ );
+ process.exit(1);
+ }
+
+ if (
+ providedFlags.has("dbSetup") &&
+ options.dbSetup === "docker" &&
+ config.runtime === "workers"
+ ) {
+ consola.fatal(
+ "Docker setup (--db-setup docker) is not compatible with Cloudflare Workers runtime. Workers runtime uses serverless databases (D1) and doesn't support local Docker containers. Please use '--db-setup d1' for SQLite or choose a different runtime.",
+ );
+ process.exit(1);
+ }
+}
+
+export function coerceBackendPresets(config: Partial) {
+ if (config.backend === "convex") {
+ config.auth = false;
+ config.database = "none";
+ config.orm = "none";
+ config.api = "none";
+ config.runtime = "none";
+ config.dbSetup = "none";
+ config.examples = ["todo"] as ProjectConfig["examples"];
+ }
+ if (config.backend === "none") {
+ config.auth = false;
+ config.database = "none";
+ config.orm = "none";
+ config.api = "none";
+ config.runtime = "none";
+ config.dbSetup = "none";
+ config.examples = [] as ProjectConfig["examples"];
+ }
+}
+
+export function incompatibleFlagsForBackend(
+ backend: ProjectConfig["backend"] | undefined,
+ providedFlags: Set,
+ options: CLIInput,
+): string[] {
+ const list: string[] = [];
+ if (backend === "convex") {
+ if (providedFlags.has("auth") && options.auth === true) list.push("--auth");
+ if (providedFlags.has("database") && options.database !== "none")
+ list.push(`--database ${options.database}`);
+ if (providedFlags.has("orm") && options.orm !== "none")
+ list.push(`--orm ${options.orm}`);
+ if (providedFlags.has("api") && options.api !== "none")
+ list.push(`--api ${options.api}`);
+ if (providedFlags.has("runtime") && options.runtime !== "none")
+ list.push(`--runtime ${options.runtime}`);
+ if (providedFlags.has("dbSetup") && options.dbSetup !== "none")
+ list.push(`--db-setup ${options.dbSetup}`);
+ }
+ if (backend === "none") {
+ if (providedFlags.has("auth") && options.auth === true) list.push("--auth");
+ if (providedFlags.has("database") && options.database !== "none")
+ list.push(`--database ${options.database}`);
+ if (providedFlags.has("orm") && options.orm !== "none")
+ list.push(`--orm ${options.orm}`);
+ if (providedFlags.has("api") && options.api !== "none")
+ list.push(`--api ${options.api}`);
+ if (providedFlags.has("runtime") && options.runtime !== "none")
+ list.push(`--runtime ${options.runtime}`);
+ if (providedFlags.has("dbSetup") && options.dbSetup !== "none")
+ list.push(`--db-setup ${options.dbSetup}`);
+ if (providedFlags.has("examples") && options.examples) {
+ const hasNonNoneExamples = options.examples.some((ex) => ex !== "none");
+ if (hasNonNoneExamples) list.push("--examples");
+ }
+ }
+ return list;
+}
+
+export function validateApiFrontendCompatibility(
+ api: API | undefined,
+ frontends: Frontend[] = [],
+) {
+ const includesNuxt = frontends.includes("nuxt");
+ const includesSvelte = frontends.includes("svelte");
+ const includesSolid = frontends.includes("solid");
+ if ((includesNuxt || includesSvelte || includesSolid) && api === "trpc") {
+ consola.fatal(
+ `tRPC API is not supported with '${includesNuxt ? "nuxt" : includesSvelte ? "svelte" : "solid"}' frontend. Please use --api orpc or --api none or remove '${includesNuxt ? "nuxt" : includesSvelte ? "svelte" : "solid"}' from --frontend.`,
+ );
+ process.exit(1);
+ }
+}
+
+export function isFrontendAllowedWithBackend(
+ frontend: Frontend,
+ backend?: ProjectConfig["backend"],
+) {
+ if (backend === "convex" && frontend === "solid") return false;
+ return true;
+}
+
+export function allowedApisForFrontends(frontends: Frontend[] = []): API[] {
+ const includesNuxt = frontends.includes("nuxt");
+ const includesSvelte = frontends.includes("svelte");
+ const includesSolid = frontends.includes("solid");
+ const base: API[] = ["trpc", "orpc", "none"];
+ if (includesNuxt || includesSvelte || includesSolid) {
+ return ["orpc", "none"];
+ }
+ return base;
+}
+
+export function isExampleTodoAllowed(
+ backend?: ProjectConfig["backend"],
+ database?: ProjectConfig["database"],
+) {
+ return !(backend !== "convex" && backend !== "none" && database === "none");
+}
+
+export function isExampleAIAllowed(
+ backend?: ProjectConfig["backend"],
+ frontends: Frontend[] = [],
+) {
+ const includesSolid = frontends.includes("solid");
+ if (backend === "elysia") return false;
+ if (includesSolid) return false;
+ return true;
+}
+
+export function validateWebDeployRequiresWebFrontend(
+ webDeploy: WebDeploy | undefined,
+ hasWebFrontendFlag: boolean,
+) {
+ if (webDeploy && webDeploy !== "none" && !hasWebFrontendFlag) {
+ consola.fatal(
+ "'--web-deploy' requires a web frontend. Please select a web frontend or set '--web-deploy none'.",
+ );
+ process.exit(1);
+ }
+}
+
+export function validateAddonsAgainstFrontends(
+ addons: Addons[] = [],
+ frontends: Frontend[] = [],
+) {
+ for (const addon of addons) {
+ if (addon === "none") continue;
+ const { isCompatible, reason } = validateAddonCompatibility(
+ addon,
+ frontends,
+ );
+ if (!isCompatible) {
+ consola.fatal(`Incompatible addon/frontend combination: ${reason}`);
+ process.exit(1);
+ }
+ }
+}
+
+export function validateExamplesCompatibility(
+ examples: string[] | undefined,
+ backend: ProjectConfig["backend"] | undefined,
+ database: ProjectConfig["database"] | undefined,
+ frontend?: Frontend[],
+) {
+ const examplesArr = examples ?? [];
+ if (examplesArr.length === 0 || examplesArr.includes("none")) return;
+ if (
+ examplesArr.includes("todo") &&
+ backend !== "convex" &&
+ backend !== "none" &&
+ database === "none"
+ ) {
+ consola.fatal(
+ "The 'todo' example requires a database if a backend (other than Convex) is present. Cannot use --examples todo when database is 'none' and a backend is selected.",
+ );
+ process.exit(1);
+ }
+ if (examplesArr.includes("ai") && backend === "elysia") {
+ consola.fatal(
+ "The 'ai' example is not compatible with the Elysia backend.",
+ );
+ process.exit(1);
+ }
+ if (examplesArr.includes("ai") && (frontend ?? []).includes("solid")) {
+ consola.fatal(
+ "The 'ai' example is not compatible with the Solid frontend.",
+ );
+ process.exit(1);
+ }
+}
diff --git a/apps/cli/src/utils/compatibility.ts b/apps/cli/src/utils/compatibility.ts
new file mode 100644
index 00000000..3f488d4c
--- /dev/null
+++ b/apps/cli/src/utils/compatibility.ts
@@ -0,0 +1,11 @@
+import type { Frontend } from "../types";
+
+export const WEB_FRAMEWORKS: readonly Frontend[] = [
+ "tanstack-router",
+ "react-router",
+ "tanstack-start",
+ "next",
+ "nuxt",
+ "svelte",
+ "solid",
+] as const;
diff --git a/apps/cli/src/utils/generate-reproducible-command.ts b/apps/cli/src/utils/generate-reproducible-command.ts
index 36d06e7a..76434959 100644
--- a/apps/cli/src/utils/generate-reproducible-command.ts
+++ b/apps/cli/src/utils/generate-reproducible-command.ts
@@ -34,15 +34,15 @@ export function generateReproducibleCommand(config: ProjectConfig): string {
flags.push(`--package-manager ${config.packageManager}`);
flags.push(config.install ? "--install" : "--no-install");
- let baseCommand = "";
+ let baseCommand = "npx create-better-t-stack@latest";
const pkgManager = config.packageManager;
- if (pkgManager === "npm") {
- baseCommand = "npx create-better-t-stack@latest";
+ if (pkgManager === "bun") {
+ baseCommand = "bun create better-t-stack@latest";
} else if (pkgManager === "pnpm") {
baseCommand = "pnpm create better-t-stack@latest";
- } else if (pkgManager === "bun") {
- baseCommand = "bun create better-t-stack@latest";
+ } else if (pkgManager === "npm") {
+ baseCommand = "npx create-better-t-stack@latest";
}
const projectPathArg = config.relativePath ? ` ${config.relativePath}` : "";
diff --git a/apps/cli/src/validation.ts b/apps/cli/src/validation.ts
index 10db63bf..830d8c69 100644
--- a/apps/cli/src/validation.ts
+++ b/apps/cli/src/validation.ts
@@ -1,6 +1,5 @@
import path from "node:path";
import { consola } from "consola";
-import { WEB_FRAMEWORKS } from "./constants";
import {
type Addons,
type API,
@@ -17,6 +16,17 @@ import {
type Runtime,
type WebDeploy,
} from "./types";
+import {
+ coerceBackendPresets,
+ ensureSingleWebAndNative,
+ incompatibleFlagsForBackend,
+ isWebFrontend,
+ validateAddonsAgainstFrontends,
+ validateApiFrontendCompatibility,
+ validateExamplesCompatibility,
+ validateWebDeployRequiresWebFrontend,
+ validateWorkersCompatibility,
+} from "./utils/compatibility-rules";
export function processAndValidateFlags(
options: CLIInput,
@@ -126,28 +136,20 @@ export function processAndValidateFlags(
const validOptions = options.frontend.filter(
(f): f is Frontend => f !== "none",
);
- const webFrontends = validOptions.filter((f) =>
- WEB_FRAMEWORKS.includes(f),
- );
- const nativeFrontends = validOptions.filter(
- (f) => f === "native-nativewind" || f === "native-unistyles",
- );
-
- if (webFrontends.length > 1) {
- consola.fatal(
- "Cannot select multiple web frameworks. Choose only one of: tanstack-router, tanstack-start, react-router, next, nuxt, svelte, solid",
- );
- process.exit(1);
- }
- if (nativeFrontends.length > 1) {
- consola.fatal(
- "Cannot select multiple native frameworks. Choose only one of: native-nativewind, native-unistyles",
- );
- process.exit(1);
- }
+ ensureSingleWebAndNative(validOptions);
config.frontend = validOptions;
}
}
+
+ if (
+ providedFlags.has("api") &&
+ providedFlags.has("frontend") &&
+ config.api &&
+ config.frontend &&
+ config.frontend.length > 0
+ ) {
+ validateApiFrontendCompatibility(config.api, config.frontend);
+ }
if (options.addons && options.addons.length > 0) {
if (options.addons.includes("none")) {
if (options.addons.length > 1) {
@@ -178,32 +180,26 @@ export function processAndValidateFlags(
}
}
- if (config.backend === "convex") {
- const incompatibleFlags: string[] = [];
-
- if (providedFlags.has("auth") && options.auth === true)
- incompatibleFlags.push("--auth");
- if (providedFlags.has("database") && options.database !== "none")
- incompatibleFlags.push(`--database ${options.database}`);
- if (providedFlags.has("orm") && options.orm !== "none")
- incompatibleFlags.push(`--orm ${options.orm}`);
- if (providedFlags.has("api") && options.api !== "none")
- incompatibleFlags.push(`--api ${options.api}`);
- if (providedFlags.has("runtime") && options.runtime !== "none")
- incompatibleFlags.push(`--runtime ${options.runtime}`);
- if (providedFlags.has("dbSetup") && options.dbSetup !== "none")
- incompatibleFlags.push(`--db-setup ${options.dbSetup}`);
-
+ if (config.backend === "convex" || config.backend === "none") {
+ const incompatibleFlags = incompatibleFlagsForBackend(
+ config.backend,
+ providedFlags,
+ options,
+ );
if (incompatibleFlags.length > 0) {
consola.fatal(
- `The following flags are incompatible with '--backend convex': ${incompatibleFlags.join(
+ `The following flags are incompatible with '--backend ${config.backend}': ${incompatibleFlags.join(
", ",
)}. Please remove them.`,
);
process.exit(1);
}
- if (providedFlags.has("frontend") && options.frontend) {
+ if (
+ config.backend === "convex" &&
+ providedFlags.has("frontend") &&
+ options.frontend
+ ) {
const incompatibleFrontends = options.frontend.filter(
(f) => f === "solid",
);
@@ -217,54 +213,15 @@ export function processAndValidateFlags(
}
}
- config.auth = false;
- config.database = "none";
- config.orm = "none";
- config.api = "none";
- config.runtime = "none";
- config.dbSetup = "none";
- config.examples = ["todo"];
- } else if (config.backend === "none") {
- const incompatibleFlags: string[] = [];
-
- if (providedFlags.has("auth") && options.auth === true)
- incompatibleFlags.push("--auth");
- if (providedFlags.has("database") && options.database !== "none")
- incompatibleFlags.push(`--database ${options.database}`);
- if (providedFlags.has("orm") && options.orm !== "none")
- incompatibleFlags.push(`--orm ${options.orm}`);
- if (providedFlags.has("api") && options.api !== "none")
- incompatibleFlags.push(`--api ${options.api}`);
- if (providedFlags.has("runtime") && options.runtime !== "none")
- incompatibleFlags.push(`--runtime ${options.runtime}`);
- if (providedFlags.has("dbSetup") && options.dbSetup !== "none")
- incompatibleFlags.push(`--db-setup ${options.dbSetup}`);
- if (providedFlags.has("examples") && options.examples) {
- const hasNonNoneExamples = options.examples.some((ex) => ex !== "none");
- if (hasNonNoneExamples) {
- incompatibleFlags.push("--examples");
- }
- }
-
- if (incompatibleFlags.length > 0) {
- consola.fatal(
- `The following flags are incompatible with '--backend none': ${incompatibleFlags.join(
- ", ",
- )}. Please remove them.`,
- );
- process.exit(1);
- }
-
- config.auth = false;
- config.database = "none";
- config.orm = "none";
- config.api = "none";
- config.runtime = "none";
- config.dbSetup = "none";
- config.examples = [];
+ coerceBackendPresets(config);
}
- if (config.orm === "mongoose" && config.database !== "mongodb") {
+ if (
+ providedFlags.has("orm") &&
+ providedFlags.has("database") &&
+ config.orm === "mongoose" &&
+ config.database !== "mongodb"
+ ) {
consola.fatal(
"Mongoose ORM requires MongoDB database. Please use '--database mongodb' or choose a different ORM.",
);
@@ -272,6 +229,8 @@ export function processAndValidateFlags(
}
if (
+ providedFlags.has("database") &&
+ providedFlags.has("orm") &&
config.database === "mongodb" &&
config.orm &&
config.orm !== "mongoose" &&
@@ -283,28 +242,50 @@ export function processAndValidateFlags(
process.exit(1);
}
- if (config.orm === "drizzle" && config.database === "mongodb") {
+ if (
+ providedFlags.has("orm") &&
+ providedFlags.has("database") &&
+ config.orm === "drizzle" &&
+ config.database === "mongodb"
+ ) {
consola.fatal(
"Drizzle ORM does not support MongoDB. Please use '--orm mongoose' or '--orm prisma' or choose a different database.",
);
process.exit(1);
}
- if (config.database && config.database !== "none" && config.orm === "none") {
+ if (
+ providedFlags.has("database") &&
+ providedFlags.has("orm") &&
+ config.database &&
+ config.database !== "none" &&
+ config.orm === "none"
+ ) {
consola.fatal(
"Database selection requires an ORM. Please choose '--orm drizzle', '--orm prisma', or '--orm mongoose'.",
);
process.exit(1);
}
- if (config.orm && config.orm !== "none" && config.database === "none") {
+ if (
+ providedFlags.has("orm") &&
+ providedFlags.has("database") &&
+ config.orm &&
+ config.orm !== "none" &&
+ config.database === "none"
+ ) {
consola.fatal(
"ORM selection requires a database. Please choose a database or set '--orm none'.",
);
process.exit(1);
}
- if (config.auth && config.database === "none") {
+ if (
+ providedFlags.has("auth") &&
+ providedFlags.has("database") &&
+ config.auth &&
+ config.database === "none"
+ ) {
consola.fatal(
"Authentication requires a database. Please choose a database or set '--no-auth'.",
);
@@ -312,6 +293,8 @@ export function processAndValidateFlags(
}
if (
+ providedFlags.has("dbSetup") &&
+ providedFlags.has("database") &&
config.dbSetup &&
config.dbSetup !== "none" &&
config.database === "none"
@@ -322,180 +305,122 @@ export function processAndValidateFlags(
process.exit(1);
}
- if (config.dbSetup === "turso" && config.database !== "sqlite") {
- consola.fatal(
- "Turso setup requires SQLite database. Please use '--database sqlite' or choose a different setup.",
- );
- process.exit(1);
- }
-
- if (config.dbSetup === "neon" && config.database !== "postgres") {
- consola.fatal(
- "Neon setup requires PostgreSQL database. Please use '--database postgres' or choose a different setup.",
- );
- process.exit(1);
- }
-
- if (config.dbSetup === "prisma-postgres" && config.database !== "postgres") {
- consola.fatal(
- "Prisma PostgreSQL setup requires PostgreSQL database. Please use '--database postgres' or choose a different setup.",
- );
- process.exit(1);
- }
-
- if (config.dbSetup === "mongodb-atlas" && config.database !== "mongodb") {
- consola.fatal(
- "MongoDB Atlas setup requires MongoDB database. Please use '--database mongodb' or choose a different setup.",
- );
- process.exit(1);
- }
-
- if (config.dbSetup === "supabase" && config.database !== "postgres") {
- consola.fatal(
- "Supabase setup requires PostgreSQL database. Please use '--database postgres' or choose a different setup.",
- );
- process.exit(1);
- }
-
- if (config.dbSetup === "d1") {
- if (config.database !== "sqlite") {
- consola.fatal(
- "Cloudflare D1 setup requires SQLite database. Please use '--database sqlite' or choose a different setup.",
- );
- process.exit(1);
- }
-
- if (config.runtime !== "workers") {
- consola.fatal(
- "Cloudflare D1 setup requires the Cloudflare Workers runtime. Please use '--runtime workers' or choose a different setup.",
- );
- process.exit(1);
- }
- }
-
- if (config.dbSetup === "docker" && config.database === "sqlite") {
- consola.fatal(
- "Docker setup is not compatible with SQLite database. SQLite is file-based and doesn't require Docker. Please use '--database postgres', '--database mysql', '--database mongodb', or choose a different setup.",
- );
- process.exit(1);
- }
-
- if (config.dbSetup === "docker" && config.runtime === "workers") {
- consola.fatal(
- "Docker setup is not compatible with Cloudflare Workers runtime. Workers runtime uses serverless databases (D1) and doesn't support local Docker containers. Please use '--db-setup d1' for SQLite or choose a different runtime.",
- );
- process.exit(1);
- }
-
if (
- providedFlags.has("runtime") &&
- options.runtime === "workers" &&
- config.backend &&
- config.backend !== "hono"
+ providedFlags.has("dbSetup") &&
+ (config.database ? providedFlags.has("database") : true) &&
+ config.dbSetup === "turso" &&
+ config.database !== "sqlite"
) {
consola.fatal(
- `Cloudflare Workers runtime (--runtime workers) is only supported with Hono backend (--backend hono). Current backend: ${config.backend}. Please use '--backend hono' or choose a different runtime.`,
+ "Turso setup requires SQLite database. Please use '--database sqlite' or choose a different setup.",
);
process.exit(1);
}
if (
- providedFlags.has("backend") &&
- config.backend &&
- config.backend !== "hono" &&
- config.runtime === "workers"
+ providedFlags.has("dbSetup") &&
+ (config.database ? providedFlags.has("database") : true) &&
+ config.dbSetup === "neon" &&
+ config.database !== "postgres"
) {
consola.fatal(
- `Backend '${config.backend}' is not compatible with Cloudflare Workers runtime. Cloudflare Workers runtime is only supported with Hono backend. Please use '--backend hono' or choose a different runtime.`,
+ "Neon setup requires PostgreSQL database. Please use '--database postgres' or choose a different setup.",
);
process.exit(1);
}
if (
- providedFlags.has("runtime") &&
- options.runtime === "workers" &&
- config.orm &&
- config.orm !== "drizzle" &&
- config.orm !== "none"
+ providedFlags.has("dbSetup") &&
+ (config.database ? providedFlags.has("database") : true) &&
+ config.dbSetup === "prisma-postgres" &&
+ config.database !== "postgres"
) {
consola.fatal(
- `Cloudflare Workers runtime (--runtime workers) is only supported with Drizzle ORM (--orm drizzle) or no ORM (--orm none). Current ORM: ${config.orm}. Please use '--orm drizzle', '--orm none', or choose a different runtime.`,
+ "Prisma PostgreSQL setup requires PostgreSQL database. Please use '--database postgres' or choose a different setup.",
);
process.exit(1);
}
if (
- providedFlags.has("orm") &&
- config.orm &&
- config.orm !== "drizzle" &&
- config.orm !== "none" &&
- config.runtime === "workers"
+ providedFlags.has("dbSetup") &&
+ (config.database ? providedFlags.has("database") : true) &&
+ config.dbSetup === "mongodb-atlas" &&
+ config.database !== "mongodb"
) {
consola.fatal(
- `ORM '${config.orm}' is not compatible with Cloudflare Workers runtime. Cloudflare Workers runtime is only supported with Drizzle ORM or no ORM. Please use '--orm drizzle', '--orm none', or choose a different runtime.`,
+ "MongoDB Atlas setup requires MongoDB database. Please use '--database mongodb' or choose a different setup.",
);
process.exit(1);
}
if (
- providedFlags.has("runtime") &&
- options.runtime === "workers" &&
- config.database === "mongodb"
+ providedFlags.has("dbSetup") &&
+ (config.database ? providedFlags.has("database") : true) &&
+ config.dbSetup === "supabase" &&
+ config.database !== "postgres"
) {
consola.fatal(
- "Cloudflare Workers runtime (--runtime workers) is not compatible with MongoDB database. MongoDB requires Prisma or Mongoose ORM, but Workers runtime only supports Drizzle ORM. Please use a different database or runtime.",
+ "Supabase setup requires PostgreSQL database. Please use '--database postgres' or choose a different setup.",
);
process.exit(1);
}
- if (
- providedFlags.has("runtime") &&
- options.runtime === "workers" &&
- config.dbSetup === "docker"
- ) {
- consola.fatal(
- "Cloudflare Workers runtime (--runtime workers) is not compatible with Docker setup. Workers runtime uses serverless databases (D1) and doesn't support local Docker containers. Please use '--db-setup d1' for SQLite or choose a different runtime.",
- );
- process.exit(1);
+ if (config.dbSetup === "d1") {
+ if (
+ (providedFlags.has("dbSetup") && providedFlags.has("database")) ||
+ (providedFlags.has("dbSetup") && !config.database)
+ ) {
+ if (config.database !== "sqlite") {
+ consola.fatal(
+ "Cloudflare D1 setup requires SQLite database. Please use '--database sqlite' or choose a different setup.",
+ );
+ process.exit(1);
+ }
+ }
+
+ if (
+ (providedFlags.has("dbSetup") && providedFlags.has("runtime")) ||
+ (providedFlags.has("dbSetup") && !config.runtime)
+ ) {
+ if (config.runtime !== "workers") {
+ consola.fatal(
+ "Cloudflare D1 setup requires the Cloudflare Workers runtime. Please use '--runtime workers' or choose a different setup.",
+ );
+ process.exit(1);
+ }
+ }
}
if (
+ providedFlags.has("dbSetup") &&
providedFlags.has("database") &&
- config.database === "mongodb" &&
- config.runtime === "workers"
+ config.dbSetup === "docker" &&
+ config.database === "sqlite"
) {
consola.fatal(
- "MongoDB database is not compatible with Cloudflare Workers runtime. MongoDB requires Prisma or Mongoose ORM, but Workers runtime only supports Drizzle ORM. Please use a different database or runtime.",
+ "Docker setup is not compatible with SQLite database. SQLite is file-based and doesn't require Docker. Please use '--database postgres', '--database mysql', '--database mongodb', or choose a different setup.",
);
process.exit(1);
}
if (
- providedFlags.has("db-setup") &&
- options.dbSetup === "docker" &&
+ providedFlags.has("dbSetup") &&
+ providedFlags.has("runtime") &&
+ config.dbSetup === "docker" &&
config.runtime === "workers"
) {
consola.fatal(
- "Docker setup (--db-setup docker) is not compatible with Cloudflare Workers runtime. Workers runtime uses serverless databases (D1) and doesn't support local Docker containers. Please use '--db-setup d1' for SQLite or choose a different runtime.",
+ "Docker setup is not compatible with Cloudflare Workers runtime. Workers runtime uses serverless databases (D1) and doesn't support local Docker containers. Please use '--db-setup d1' for SQLite or choose a different runtime.",
);
process.exit(1);
}
+ validateWorkersCompatibility(providedFlags, options, config);
+
const hasWebFrontendFlag = (config.frontend ?? []).some((f) =>
- WEB_FRAMEWORKS.includes(f),
+ isWebFrontend(f),
);
-
- if (
- config.webDeploy &&
- config.webDeploy !== "none" &&
- !hasWebFrontendFlag &&
- providedFlags.has("frontend")
- ) {
- consola.fatal(
- "'--web-deploy' requires a web frontend. Please select a web frontend or set '--web-deploy none'.",
- );
- process.exit(1);
- }
+ validateWebDeployRequiresWebFrontend(config.webDeploy, hasWebFrontendFlag);
return config;
}
@@ -505,140 +430,20 @@ export function validateConfigCompatibility(config: Partial) {
const effectiveBackend = config.backend;
const effectiveFrontend = config.frontend;
const effectiveApi = config.api;
- const effectiveRuntime = config.runtime;
- if (effectiveRuntime === "workers" && effectiveBackend !== "hono") {
- consola.fatal(
- `Cloudflare Workers runtime is only supported with Hono backend. Current backend: ${effectiveBackend}. Please use a different runtime or change to Hono backend.`,
- );
- process.exit(1);
- }
-
- const effectiveOrm = config.orm;
- if (
- effectiveRuntime === "workers" &&
- effectiveOrm !== "drizzle" &&
- effectiveOrm !== "none"
- ) {
- consola.fatal(
- `Cloudflare Workers runtime is only supported with Drizzle ORM or no ORM. Current ORM: ${effectiveOrm}. Please use a different runtime or change to Drizzle ORM or no ORM.`,
- );
- process.exit(1);
- }
-
- if (effectiveRuntime === "workers" && effectiveDatabase === "mongodb") {
- consola.fatal(
- "Cloudflare Workers runtime is not compatible with MongoDB database. MongoDB requires Prisma or Mongoose ORM, but Workers runtime only supports Drizzle ORM. Please use a different database or runtime.",
- );
- process.exit(1);
- }
-
- if (effectiveRuntime === "workers" && config.dbSetup === "docker") {
- consola.fatal(
- "Cloudflare Workers runtime is not compatible with Docker setup. Workers runtime uses serverless databases (D1) and doesn't support local Docker containers. Please use a different runtime or change to D1 database setup.",
- );
- process.exit(1);
- }
-
- const includesNuxt = effectiveFrontend?.includes("nuxt");
- const includesSvelte = effectiveFrontend?.includes("svelte");
- const includesSolid = effectiveFrontend?.includes("solid");
-
- if (
- (includesNuxt || includesSvelte || includesSolid) &&
- effectiveApi === "trpc"
- ) {
- consola.fatal(
- `tRPC API is not supported with '${
- includesNuxt ? "nuxt" : includesSvelte ? "svelte" : "solid"
- }' frontend. Please use --api orpc or --api none or remove '${
- includesNuxt ? "nuxt" : includesSvelte ? "svelte" : "solid"
- }' from --frontend.`,
- );
- process.exit(1);
- }
+ validateApiFrontendCompatibility(effectiveApi, effectiveFrontend);
if (config.addons && config.addons.length > 0) {
- const webSpecificAddons = ["pwa", "tauri"];
- const hasWebSpecificAddons = config.addons.some((addon) =>
- webSpecificAddons.includes(addon),
- );
- const hasCompatibleWebFrontend = effectiveFrontend?.some((f) => {
- const isPwaCompatible =
- f === "tanstack-router" ||
- f === "react-router" ||
- f === "solid" ||
- f === "next";
- const isTauriCompatible =
- f === "tanstack-router" ||
- f === "react-router" ||
- f === "nuxt" ||
- f === "svelte" ||
- f === "solid" ||
- f === "next";
-
- if (config.addons?.includes("pwa") && config.addons?.includes("tauri")) {
- return isPwaCompatible && isTauriCompatible;
- }
- if (config.addons?.includes("pwa")) {
- return isPwaCompatible;
- }
- if (config.addons?.includes("tauri")) {
- return isTauriCompatible;
- }
- return true;
- });
-
- if (hasWebSpecificAddons && !hasCompatibleWebFrontend) {
- let incompatibleReason = "Selected frontend is not compatible.";
- if (config.addons.includes("pwa")) {
- incompatibleReason =
- "PWA requires tanstack-router, react-router, next, or solid.";
- }
- if (config.addons.includes("tauri")) {
- incompatibleReason =
- "Tauri requires tanstack-router, react-router, nuxt, svelte, solid, or next.";
- }
- consola.fatal(
- `Incompatible addon/frontend combination: ${incompatibleReason}`,
- );
- process.exit(1);
- }
-
+ validateAddonsAgainstFrontends(config.addons, effectiveFrontend);
config.addons = [...new Set(config.addons)];
}
- if (
- config.examples &&
- config.examples.length > 0 &&
- !config.examples.includes("none")
- ) {
- if (
- config.examples.includes("todo") &&
- effectiveBackend !== "convex" &&
- effectiveBackend !== "none" &&
- effectiveDatabase === "none"
- ) {
- consola.fatal(
- "The 'todo' example requires a database if a backend (other than Convex) is present. Cannot use --examples todo when database is 'none' and a backend is selected.",
- );
- process.exit(1);
- }
-
- if (config.examples.includes("ai") && effectiveBackend === "elysia") {
- consola.fatal(
- "The 'ai' example is not compatible with the Elysia backend.",
- );
- process.exit(1);
- }
-
- if (config.examples.includes("ai") && includesSolid) {
- consola.fatal(
- "The 'ai' example is not compatible with the Solid frontend.",
- );
- process.exit(1);
- }
- }
+ validateExamplesCompatibility(
+ config.examples ?? [],
+ effectiveBackend,
+ effectiveDatabase,
+ effectiveFrontend ?? [],
+ );
}
export function getProvidedFlags(options: CLIInput): Set {
diff --git a/apps/web/content/docs/analytics.mdx b/apps/web/content/docs/analytics.mdx
new file mode 100644
index 00000000..162c132c
--- /dev/null
+++ b/apps/web/content/docs/analytics.mdx
@@ -0,0 +1,71 @@
+---
+title: Analytics & Telemetry
+description: What we collect, how to disable it, and where to view aggregated insights
+---
+
+## What is collected
+
+On successful project creation, the CLI sends a single event (`project_created`) with:
+
+- Selected options (stack choices): `frontend`, `backend`, `runtime`, `database`, `orm`, `api`, `auth`, `addons`, `examples`, `dbSetup`, `webDeploy`, `packageManager`
+- Environment data: `cli_version`, `node_version`, `platform`
+- A random session id: `distinct_id` like `cli_`
+- IP removed: `$ip: null`
+
+Not collected:
+
+- Project name, path, or file contents (explicitly omitted)
+- Secrets or environment variables from your machine
+
+
+
+## Disable telemetry
+
+Telemetry is enabled by default. To disable:
+
+
+
+ ```bash
+ # Disable for a single run
+ BTS_TELEMETRY_DISABLED=1 bun create better-t-stack@latest
+ ```
+
+
+ ```bash
+ # Disable for a single run
+ BTS_TELEMETRY_DISABLED=1 pnpm create better-t-stack@latest
+ ```
+
+
+ ```bash
+ # Disable for a single run
+ BTS_TELEMETRY_DISABLED=1 npx create-better-t-stack@latest
+ ```
+
+
+
+Add `export BTS_TELEMETRY_DISABLED=1` to your shell profile to make it permanent.
+
+## Where to view analytics
+
+- Charts: [`/analytics`](/analytics)
+- Raw JSON snapshot: `https://r2.amanv.dev/analytics-data.json`
+- CSV export: `https://r2.amanv.dev/export.csv`
+
+Notes:
+
+- Aggregates are periodically regenerated from incoming events
+- Raw data is not publicly exposed; the `/analytics` page presents only summary statistics
+
+## Full transparency
+
+Single event per scaffold; randomized id; no IP or project identifiers. See source code below.
+
+If in doubt, set `BTS_TELEMETRY_DISABLED=1` and proceed. You can still use all CLI features.
+
+## Source code
+
+- CLI event sender: [`apps/cli/src/utils/analytics.ts`](https://github.com/AmanVarshney01/create-better-t-stack/blob/main/apps/cli/src/utils/analytics.ts)
+- Telemetry toggle logic: [`apps/cli/src/utils/telemetry.ts`](https://github.com/AmanVarshney01/create-better-t-stack/blob/main/apps/cli/src/utils/telemetry.ts)
+- Aggregation script (builds the charts data): [`apps/web/scripts/generate-analytics.ts`](https://github.com/AmanVarshney01/create-better-t-stack/blob/main/apps/web/scripts/generate-analytics.ts)
+
diff --git a/apps/web/content/docs/bts-config.mdx b/apps/web/content/docs/bts-config.mdx
new file mode 100644
index 00000000..ab2c4361
--- /dev/null
+++ b/apps/web/content/docs/bts-config.mdx
@@ -0,0 +1,54 @@
+---
+title: bts.jsonc
+description: What bts.jsonc does and why it matters
+---
+
+## What is it?
+
+`bts.jsonc` is a small config file written to your project root when you create a project. It captures the stack choices you selected (frontend, backend, API, DB/ORM, auth, addons, etc.). The file uses JSONC (JSON with comments) and includes a schema for editor hints.
+
+Where: `./bts.jsonc`
+
+## Why it exists
+
+- Required for the `add` command to detect your current stack
+- Helps validate compatibility and pre‑fill sensible defaults
+
+If `bts.jsonc` is missing, the `add` command cannot run because the project cannot be detected.
+
+## Safe to delete (with a caveat)
+
+It’s safe to delete for normal development; the generated code in `apps/*` and `packages/*` remains the source of truth. However, if you plan to use the `add` command later, you must keep `bts.jsonc` (or recreate it) so the CLI can detect your project.
+
+## Format
+
+The file is JSONC with comments enabled and includes a `$schema` URL for tooling.
+
+```jsonc
+// Better-T-Stack configuration file
+// safe to delete
+{
+ "$schema": "https://r2.better-t-stack.dev/schema.json",
+ "version": "x.y.z",
+ "createdAt": "2025-01-01T00:00:00.000Z",
+ "frontend": ["tanstack-router"],
+ "backend": "hono",
+ "runtime": "bun",
+ "database": "sqlite",
+ "orm": "drizzle",
+ "api": "trpc",
+ "auth": true,
+ "addons": ["turborepo"],
+ "examples": [],
+ "dbSetup": "none",
+ "webDeploy": "none",
+ "packageManager": "bun"
+}
+```
+
+Notes:
+- Values mirror what you selected during project creation
+- The file may be updated when you run `add` (e.g., addons or webDeploy)
+
+See also: [`add` command](/docs/cli/add)
+
diff --git a/apps/web/content/docs/cli-commands.mdx b/apps/web/content/docs/cli-commands.mdx
deleted file mode 100644
index 8c075d84..00000000
--- a/apps/web/content/docs/cli-commands.mdx
+++ /dev/null
@@ -1,462 +0,0 @@
----
-title: CLI Commands
-description: Complete reference for all Better-T-Stack CLI commands and options
----
-
-## Commands Overview
-
-| Command | Description |
-|---------|-------------|
-| `init` (default) | Create a new Better-T-Stack project |
-| `add` | Add addons or deployment configurations to existing projects |
-| `sponsors` | Display project sponsors |
-| `docs` | Open documentation in browser |
-| `builder` | Open web-based stack builder |
-
----
-
-## `init` - Create Project (Default)
-
-The primary command for creating new Better-T-Stack projects.
-
-### Basic Usage
-
-```bash
-# Interactive setup
-npx create-better-t-stack@latest
-
-# With project name
-npx create-better-t-stack@latest my-project
-
-# With specific directory
-npx create-better-t-stack@latest ./path/to/project
-
-# Use current directory
-npx create-better-t-stack@latest .
-```
-
-### Flags Reference
-
-#### General Options
-
-| Flag | Type | Default | Description |
-|------|------|---------|-------------|
-| `--yes, -y` | boolean | `false` | Skip prompts, use defaults |
-| `--help, -h` | boolean | - | Show help information |
-| `--version, -V` | boolean | - | Show CLI version |
-
-#### Frontend Options
-
-| Flag | Values | Default | Description |
-|------|--------|---------|-------------|
-| `--frontend` | Multiple values | `tanstack-router` | Frontend frameworks to include |
-
-**Available Frontend Values:**
-- `tanstack-router` - React with TanStack Router
-- `react-router` - React with React Router
-- `tanstack-start` - React with TanStack Start (SSR)
-- `next` - Next.js framework
-- `nuxt` - Vue.js with Nuxt
-- `svelte` - SvelteKit
-- `solid` - SolidJS
-- `native-nativewind` - React Native with NativeWind
-- `native-unistyles` - React Native with Unistyles
-- `none` - No frontend
-
-**Examples:**
-```bash
-# Single web frontend
---frontend tanstack-router
-
-# Web + Mobile
---frontend tanstack-router native-nativewind
-
-# Multiple frontends
---frontend next solid
-
-# No frontend (API-only)
---frontend none
-```
-
-#### Backend Options
-
-| Flag | Values | Default | Description |
-|------|--------|---------|-------------|
-| `--backend` | Single value | `hono` | Backend framework |
-
-**Available Backend Values:**
-- `hono` - Hono web framework
-- `express` - Express.js
-- `fastify` - Fastify framework
-- `elysia` - Elysia framework
-- `next` - Next.js API routes
-- `convex` - Convex backend-as-a-service
-- `none` - No backend
-
-**Examples:**
-```bash
---backend hono
---backend convex
---backend none
-```
-
-#### Runtime Options
-
-| Flag | Values | Default | Description |
-|------|--------|---------|-------------|
-| `--runtime` | Single value | `bun` | Runtime environment |
-
-**Available Runtime Values:**
-- `bun` - Bun runtime
-- `node` - Node.js runtime
-- `workers` - Cloudflare Workers (Hono only)
-- `none` - No runtime (Convex/none backend)
-
-**Examples:**
-```bash
---runtime bun
---runtime workers # Only with --backend hono
-```
-
-#### Database Options
-
-| Flag | Values | Default | Description |
-|------|--------|---------|-------------|
-| `--database` | Single value | `sqlite` | Database type |
-
-**Available Database Values:**
-- `sqlite` - SQLite database
-- `postgres` - PostgreSQL
-- `mysql` - MySQL
-- `mongodb` - MongoDB
-- `none` - No database
-
-**Examples:**
-```bash
---database postgres
---database none
-```
-
-#### ORM Options
-
-| Flag | Values | Default | Description |
-|------|--------|---------|-------------|
-| `--orm` | Single value | `drizzle` | ORM/Database toolkit |
-
-**Available ORM Values:**
-- `drizzle` - Drizzle ORM (TypeScript-first)
-- `prisma` - Prisma ORM (feature-rich)
-- `mongoose` - Mongoose (MongoDB only)
-- `none` - No ORM
-
-**Examples:**
-```bash
---orm drizzle
---orm prisma
---orm none
-```
-
-#### API Layer Options
-
-| Flag | Values | Default | Description |
-|------|--------|---------|-------------|
-| `--api` | Single value | `trpc` | API layer type |
-
-**Available API Values:**
-- `trpc` - tRPC (end-to-end type safety)
-- `orpc` - oRPC (OpenAPI compatible)
-- `none` - No API layer
-
-**Examples:**
-```bash
---api trpc
---api orpc
---api none
-```
-
-#### Authentication Options
-
-| Flag | Type | Default | Description |
-|------|------|---------|-------------|
-| `--auth` | boolean | `true` | Enable authentication |
-| `--no-auth` | boolean | - | Disable authentication |
-
-**Examples:**
-```bash
---auth # Enable auth
---no-auth # Disable auth
-```
-
-#### Addons Options
-
-| Flag | Values | Default | Description |
-|------|--------|---------|-------------|
-| `--addons` | Multiple values | `turborepo` | Additional features |
-
-**Available Addon Values:**
-- `turborepo` - Turborepo build system
-- `pwa` - Progressive Web App support
-- `tauri` - Desktop app with Tauri
-- `biome` - Biome linter/formatter
-- `husky` - Git hooks with Husky
-- `starlight` - Documentation site
-- `none` - No addons
-
-**Examples:**
-```bash
---addons turborepo pwa
---addons biome husky
---addons none
-```
-
-#### Examples Options
-
-| Flag | Values | Default | Description |
-|------|--------|---------|-------------|
-| `--examples` | Multiple values | `[]` | Example applications |
-
-**Available Example Values:**
-- `todo` - Todo CRUD application
-- `ai` - AI chat interface
-- `none` - No examples
-
-**Examples:**
-```bash
---examples todo
---examples todo ai
---examples none
-```
-
-#### Database Setup Options
-
-| Flag | Values | Default | Description |
-|------|--------|---------|-------------|
-| `--db-setup` | Single value | `none` | Database hosting setup |
-
-**Available Database Setup Values:**
-- `turso` - Turso SQLite hosting
-- `neon` - Neon PostgreSQL
-- `supabase` - Supabase PostgreSQL
-- `prisma-postgres` - Prisma PostgreSQL
-- `mongodb-atlas` - MongoDB Atlas
-- `d1` - Cloudflare D1 (Workers only)
-- `docker` - Local Docker setup
-- `none` - Manual setup
-
-**Examples:**
-```bash
---db-setup neon
---db-setup docker
---db-setup none
-```
-
-#### Deployment Options
-
-| Flag | Values | Default | Description |
-|------|--------|---------|-------------|
-| `--web-deploy` | Single value | `none` | Web deployment setup |
-
-**Available Deployment Values:**
-- `workers` - Cloudflare Workers
-- `none` - No deployment setup
-
-**Examples:**
-```bash
---web-deploy workers
---web-deploy none
-```
-
-#### Project Management Options
-
-| Flag | Type | Default | Description |
-|------|------|---------|-------------|
-| `--git` | boolean | `true` | Initialize git repository |
-| `--no-git` | boolean | - | Skip git initialization |
-| `--install` | boolean | `true` | Install dependencies |
-| `--no-install` | boolean | - | Skip dependency installation |
-| `--package-manager` | string | auto-detect | Package manager to use |
-
-**Package Manager Values:**
-- `npm` - Use npm
-- `pnpm` - Use pnpm
-- `bun` - Use bun
-
-**Examples:**
-```bash
---git --install --package-manager pnpm
---no-git --no-install
-```
-
----
-
-## `add` - Add to Existing Project
-
-Add addons or deployment configurations to existing Better-T-Stack projects.
-
-### Usage
-
-```bash
-# Interactive addon selection
-npx create-better-t-stack@latest add
-
-# Add specific addons
-npx create-better-t-stack@latest add --addons pwa tauri
-
-# Add deployment
-npx create-better-t-stack@latest add --web-deploy workers
-
-# Add both
-npx create-better-t-stack@latest add --addons biome --web-deploy workers
-```
-
-### Flags
-
-| Flag | Values | Description |
-|------|--------|-------------|
-| `--addons` | Multiple values | Addons to add (same as init) |
-| `--web-deploy` | Single value | Deployment to add |
-| `--project-dir` | string | Target project directory (default: current) |
-| `--install` | boolean | Install dependencies after adding |
-| `--no-install` | boolean | Skip dependency installation |
-| `--package-manager` | string | Package manager to use |
-
-### Examples
-
-```bash
-# Add PWA support to current project
-npx create-better-t-stack@latest add --addons pwa
-
-# Add multiple addons with dependency installation
-npx create-better-t-stack@latest add --addons biome husky --install
-
-# Add to specific project directory
-npx create-better-t-stack@latest add --project-dir ./my-project --addons tauri
-```
-
----
-
-## `sponsors` - View Sponsors
-
-Display Better-T-Stack project sponsors.
-
-### Usage
-
-```bash
-npx create-better-t-stack@latest sponsors
-```
-
-Shows a list of project sponsors with their GitHub profiles and websites.
-
----
-
-## `docs` - Open Documentation
-
-Open Better-T-Stack documentation in your default browser.
-
-### Usage
-
-```bash
-npx create-better-t-stack@latest docs
-```
-
-Opens: https://better-t-stack.dev/docs
-
----
-
-## `builder` - Open Stack Builder
-
-Open the web-based interactive stack builder.
-
-### Usage
-
-```bash
-npx create-better-t-stack@latest builder
-```
-
-Opens: https://better-t-stack.dev/new
-
-The web builder provides a visual interface for configuring your stack and generates the corresponding CLI command.
-
----
-
-## Complete Examples
-
-### Full-Stack Web Application
-
-```bash
-npx create-better-t-stack@latest my-webapp \
- --frontend tanstack-router \
- --backend hono \
- --runtime bun \
- --database postgres \
- --orm drizzle \
- --api trpc \
- --auth \
- --db-setup neon \
- --addons pwa turborepo \
- --examples todo ai
-```
-
-### Mobile + Web Application
-
-```bash
-npx create-better-t-stack@latest my-mobile-app \
- --frontend tanstack-router native-nativewind \
- --backend hono \
- --database sqlite \
- --orm drizzle \
- --auth \
- --db-setup turso \
- --addons turborepo
-```
-
-### Cloudflare Workers Project
-
-```bash
-npx create-better-t-stack@latest my-workers-app \
- --frontend tanstack-router \
- --backend hono \
- --runtime workers \
- --database sqlite \
- --orm drizzle \
- --db-setup d1 \
- --web-deploy workers
-```
-
-### API-Only Project
-
-```bash
-npx create-better-t-stack@latest my-api \
- --frontend none \
- --backend fastify \
- --runtime node \
- --database postgres \
- --orm prisma \
- --api trpc \
- --db-setup docker
-```
-
-### Quick Defaults
-
-```bash
-# Use all defaults with immediate setup
-npx create-better-t-stack@latest my-project --yes
-
-# Convex full-stack (automatically configures compatible options)
-npx create-better-t-stack@latest my-convex-app --backend convex
-```
-
----
-
-## Compatibility Notes
-
-Some options have compatibility requirements:
-
-- **Cloudflare Workers**: Only with `--backend hono`, `--orm drizzle`, `--runtime workers`
-- **MongoDB**: Requires `--orm mongoose` or `--orm prisma`
-- **Convex**: Incompatible with custom database/ORM/API options
-- **PWA**: Requires compatible web frontend
-- **Tauri**: Requires compatible web frontend
-- **AI Examples**: Not compatible with `--backend elysia` or `--frontend solid`
-
-The CLI will validate compatibility and show helpful error messages for invalid combinations.
diff --git a/apps/web/content/docs/cli/add.mdx b/apps/web/content/docs/cli/add.mdx
new file mode 100644
index 00000000..388a897e
--- /dev/null
+++ b/apps/web/content/docs/cli/add.mdx
@@ -0,0 +1,68 @@
+---
+title: add
+description: Add addons or deployment to an existing project
+---
+
+## Usage
+
+
+
+ ```bash
+ bun create better-t-stack@latest add
+ ```
+
+
+ ```bash
+ pnpm create better-t-stack@latest add
+ ```
+
+
+ ```bash
+ npx create-better-t-stack@latest add
+ ```
+
+
+
+## Flags
+
+### Addons
+
+- `--addons` Multiple values to add features
+ - Values: `pwa`, `tauri`, `starlight`, `biome`, `husky`, `turborepo`, `fumadocs`, `ultracite`, `oxlint`, `none`
+ - Do not combine `none` with other values
+
+### Deployment
+
+- `--web-deploy` One of: `workers`, `none`
+ - Requires that the project includes a web frontend
+
+### Project directory and install
+
+- `--project-dir` Path to target project (default: current directory)
+- `--install` / `--no-install` Install dependencies after applying changes
+- `--package-manager` One of: `bun`, `pnpm`, `npm`
+
+## Examples
+
+```bash
+# Add PWA and Turborepo to the current project
+bun create better-t-stack@latest add --addons pwa turborepo --install
+```
+
+```bash
+# Add Cloudflare Workers deployment
+bun create better-t-stack@latest add --web-deploy workers
+```
+
+```bash
+# Operate on a specific project directory using bun
+bun create better-t-stack@latest add --project-dir ./apps/web --addons biome --package-manager bun
+```
+
+## Compatibility notes
+
+- Web deployment requires a web frontend to be present
+- Addons must be compatible with the selected frontend; the CLI validates this and fails with a clear error if incompatible
+
+For general compatibility rules, see the main CLI reference.
+
diff --git a/apps/web/content/docs/cli/builder.mdx b/apps/web/content/docs/cli/builder.mdx
new file mode 100644
index 00000000..1d30afa4
--- /dev/null
+++ b/apps/web/content/docs/cli/builder.mdx
@@ -0,0 +1,26 @@
+---
+title: builder
+description: Open the web-based stack builder
+---
+
+## Usage
+
+
+
+ ```bash
+ bun create better-t-stack@latest builder
+ ```
+
+
+ ```bash
+ pnpm create better-t-stack@latest builder
+ ```
+
+
+ ```bash
+ npx create-better-t-stack@latest builder
+ ```
+
+
+
+This command has no flags.
diff --git a/apps/web/content/docs/cli/docs.mdx b/apps/web/content/docs/cli/docs.mdx
new file mode 100644
index 00000000..649e3e75
--- /dev/null
+++ b/apps/web/content/docs/cli/docs.mdx
@@ -0,0 +1,26 @@
+---
+title: docs
+description: Open the documentation
+---
+
+## Usage
+
+
+
+ ```bash
+ bun create better-t-stack@latest docs
+ ```
+
+
+ ```bash
+ pnpm create better-t-stack@latest docs
+ ```
+
+
+ ```bash
+ npx create-better-t-stack@latest docs
+ ```
+
+
+
+This command has no flags.
diff --git a/apps/web/content/docs/cli/index.mdx b/apps/web/content/docs/cli/index.mdx
new file mode 100644
index 00000000..94774e6b
--- /dev/null
+++ b/apps/web/content/docs/cli/index.mdx
@@ -0,0 +1,23 @@
+---
+title: CLI
+description: Command reference index
+---
+
+
+
+ Create a new Better‑T‑Stack project (prompts or --yes)
+
+
+ Add addons or deployment to an existing project
+
+
+ Open the web-based Stack Builder
+
+
+ Open documentation
+
+
+ View project sponsors
+
+
+
diff --git a/apps/web/content/docs/cli/init.mdx b/apps/web/content/docs/cli/init.mdx
new file mode 100644
index 00000000..f0940190
--- /dev/null
+++ b/apps/web/content/docs/cli/init.mdx
@@ -0,0 +1,151 @@
+---
+title: init
+description: Create a new Better-T-Stack project
+---
+
+## Usage
+
+
+
+ ```bash
+ bun create better-t-stack@latest [project-directory]
+ ```
+
+
+ ```bash
+ pnpm create better-t-stack@latest [project-directory]
+ ```
+
+
+ ```bash
+ npx create-better-t-stack@latest [project-directory]
+ ```
+
+
+
+You can pass `.` to use the current directory.
+
+### Skip prompts
+
+```bash
+bun create better-t-stack@latest my-app --yes
+```
+
+## Flags Reference
+
+### General
+
+- `--yes, -y` Skip all prompts and use defaults
+- `--help, -h` Show help
+- `--version, -V` Show CLI version
+
+### Frontend
+
+- `--frontend` Choose one web frontend and optionally one native frontend
+ - Web: `tanstack-router`, `react-router`, `tanstack-start`, `next`, `nuxt`, `svelte`, `solid`
+ - Native: `native-nativewind`, `native-unistyles`
+ - Special: `none`
+ - Notes: At most one from each group; do not combine `none` with others
+
+### Backend
+
+- `--backend` One of: `hono`, `express`, `fastify`, `next`, `elysia`, `convex`, `none`
+
+### Runtime
+
+- `--runtime` One of: `bun`, `node`, `workers`, `none`
+ - `workers` only with `--backend hono`
+ - `none` only with `--backend convex` or `--backend none`
+
+### Database
+
+- `--database` One of: `sqlite`, `postgres`, `mysql`, `mongodb`, `none`
+
+### ORM
+
+- `--orm` One of: `drizzle`, `prisma`, `mongoose`, `none`
+ - `mongoose` requires `--database mongodb`
+ - `drizzle` is not compatible with `--database mongodb`
+
+### API
+
+- `--api` One of: `trpc`, `orpc`, `none`
+ - Use `orpc` with `nuxt`, `svelte`, or `solid` (tRPC not supported there)
+
+### Authentication
+
+- `--auth` Enable auth
+- `--no-auth` Disable auth
+ - Auth requires a non-`none` database
+
+### Addons
+
+- `--addons` Multiple values: `pwa`, `tauri`, `starlight`, `biome`, `husky`, `turborepo`, `fumadocs`, `ultracite`, `oxlint`, `none`
+ - Do not combine `none` with other values
+
+### Examples
+
+- `--examples` Multiple values: `todo`, `ai`, `none`
+ - Do not combine `none` with other values
+
+### Database setup
+
+- `--db-setup` One of: `turso`, `neon`, `prisma-postgres`, `mongodb-atlas`, `supabase`, `d1`, `docker`, `none`
+ - `turso` → requires `--database sqlite`
+ - `neon`, `prisma-postgres`, `supabase` → require `--database postgres`
+ - `mongodb-atlas` → requires `--database mongodb`
+ - `d1` → requires `--database sqlite` and `--runtime workers`
+ - `docker` → not compatible with `--database sqlite` or `--runtime workers`
+
+### Web deployment
+
+- `--web-deploy` One of: `workers`, `none`
+ - Requires selecting a web frontend
+
+### Project setup
+
+- `--git` / `--no-git` Initialize git repository
+- `--install` / `--no-install` Install dependencies
+- `--package-manager` One of: `bun`, `pnpm`, `npm`
+
+## Examples
+
+```bash
+# Full-stack web app
+bun create better-t-stack@latest my-webapp \
+ --frontend tanstack-router \
+ --backend hono \
+ --runtime bun \
+ --database postgres \
+ --orm drizzle \
+ --api trpc \
+ --auth \
+ --db-setup neon \
+ --addons pwa turborepo \
+ --examples todo
+```
+
+```bash
+# Cloudflare Workers
+bun create better-t-stack@latest my-workers \
+ --frontend tanstack-router \
+ --backend hono \
+ --runtime workers \
+ --database sqlite \
+ --orm drizzle \
+ --db-setup d1 \
+ --web-deploy workers
+```
+
+## Compatibility notes
+
+- Workers runtime only with `--backend hono` and `--orm drizzle` or `--orm none`
+- MongoDB requires `--orm mongoose` or `--orm prisma`
+- Convex backend forces: no auth, no db, no orm, no api, no runtime, no db-setup; Solid is not supported
+- Todo example requires a database when a non-Convex backend is selected
+- AI example is not compatible with `--backend elysia` or `--frontend solid`
+
+The CLI validates incompatible combinations and fails fast with clear messages.
+
+See also: Compatibility overview in the main CLI reference.
+
diff --git a/apps/web/content/docs/cli/meta.json b/apps/web/content/docs/cli/meta.json
new file mode 100644
index 00000000..fd5ecdab
--- /dev/null
+++ b/apps/web/content/docs/cli/meta.json
@@ -0,0 +1,5 @@
+{
+ "title": "CLI",
+ "defaultOpen": true,
+ "pages": ["index", "init", "add", "builder", "docs", "sponsors"]
+}
diff --git a/apps/web/content/docs/cli/sponsors.mdx b/apps/web/content/docs/cli/sponsors.mdx
new file mode 100644
index 00000000..4e8f8025
--- /dev/null
+++ b/apps/web/content/docs/cli/sponsors.mdx
@@ -0,0 +1,26 @@
+---
+title: sponsors
+description: View project sponsors
+---
+
+## Usage
+
+
+
+ ```bash
+ bun create better-t-stack@latest sponsors
+ ```
+
+
+ ```bash
+ pnpm create better-t-stack@latest sponsors
+ ```
+
+
+ ```bash
+ npx create-better-t-stack@latest sponsors
+ ```
+
+
+
+This command has no flags.
diff --git a/apps/web/content/docs/compatibility.mdx b/apps/web/content/docs/compatibility.mdx
new file mode 100644
index 00000000..4eddcfe8
--- /dev/null
+++ b/apps/web/content/docs/compatibility.mdx
@@ -0,0 +1,29 @@
+---
+title: Compatibility
+description: Valid and invalid combinations across frontend, backend, runtime, database, and addons
+---
+
+## Rules
+
+- **Convex backend**: Disables authentication, database, ORM, and API options
+- **Backend `none`**: Forces API, ORM, database, authentication, and runtime to `none`; disables examples
+- **Frontend `none`**: Backend-only project; PWA/Tauri/examples may be disabled
+- **API `none`**: No tRPC/oRPC setup; use framework-native APIs
+- **Database `none`**: Disables ORM and authentication
+- **ORM `none`**: No ORM setup; manage DB manually
+- **Runtime `none`**: Only with Convex backend or when backend is `none`
+
+## Cloudflare Workers
+
+- Backend: `hono` only
+- Database: `sqlite` with Cloudflare D1
+- ORM: `drizzle` (or none)
+- Not compatible with MongoDB
+
+## Framework Notes
+
+- SvelteKit, Nuxt, and SolidJS frontends are only compatible with `orpc` API layer
+- PWA addon requires React (TanStack Router/React Router) or SolidJS
+- Tauri addon requires React (TanStack Router/React Router), Nuxt, SvelteKit, SolidJS, or Next.js
+- AI example is not compatible with Elysia backend or SolidJS frontend
+
diff --git a/apps/web/content/docs/contributing.mdx b/apps/web/content/docs/contributing.mdx
new file mode 100644
index 00000000..ec46e4bd
--- /dev/null
+++ b/apps/web/content/docs/contributing.mdx
@@ -0,0 +1,94 @@
+---
+title: Contributing
+description: How to set up your environment and contribute changes
+---
+
+## Overview
+
+This project is a monorepo with two main apps:
+
+- CLI: `apps/cli`
+- Documentation site: `apps/web`
+
+> Note: Planning to add a new feature? Please open an issue first to confirm it aligns with the project's future goals. We don't want you to spend time on work that might not land.
+
+## Setup
+
+### Prerequisites
+
+- Node.js 20+
+- Bun (recommended)
+- Git
+
+### Install
+
+```bash
+git clone https://github.com/AmanVarshney01/create-better-t-stack.git
+cd create-better-t-stack
+bun install
+```
+
+## Develop the CLI
+
+```bash
+cd apps/cli
+# optional global link for testing anywhere
+bun link
+# run in watch mode
+bun dev:cli
+```
+
+## Develop the Docs
+
+```bash
+# from repo root
+bun dev:web
+```
+
+## Contribution Flow
+
+1. Open an issue/discussion before starting major work
+2. Create a feature branch
+3. Make changes following existing code style
+4. Update docs as needed
+5. Test and format
+
+```bash
+# CLI
+cd apps/cli && bun dev:cli
+
+# Web
+bun dev:web
+
+# Format
+bun run format
+
+# Type checks
+bun check
+```
+
+6. (CLI changes) Add a changeset
+
+```bash
+bunx changeset select create-better-t-stack
+# Choose 'patch' for small fixes, 'minor' for features
+# Never choose 'major'
+```
+
+7. Commit and push
+
+```bash
+git add .
+git commit -m "feat(web): ..." # or fix(cli): ...
+git push origin
+```
+
+8. Open a Pull Request and link any related issues
+
+## Help
+
+- Issues and Discussions on GitHub
+- Discord: https://discord.gg/ZYsbjpDaM5
+
+See full contributor guide in the repository: `.github/CONTRIBUTING.md`.
+
diff --git a/apps/web/content/docs/faq.mdx b/apps/web/content/docs/faq.mdx
index d6d5e218..7b939524 100644
--- a/apps/web/content/docs/faq.mdx
+++ b/apps/web/content/docs/faq.mdx
@@ -1,334 +1,46 @@
---
title: Frequently Asked Questions
-description: Common questions and answers about Better-T-Stack CLI
+description: Short answers to common beginner questions
---
-## General Questions
+## General
-### What is Better-T-Stack?
+### What is Better‑T‑Stack?
+An opinionated CLI that scaffolds full‑stack TypeScript projects (frontend, backend, API, DB/ORM, auth, addons) with a clean monorepo. See the Quick Start on the docs home.
-Better-T-Stack is a modern CLI tool that helps you scaffold end-to-end type-safe TypeScript projects. It provides opinionated, production-ready configurations for full-stack applications with support for multiple frontend frameworks, backend frameworks, databases, and deployment options.
+### Do I need to install anything globally?
+No. Run the CLI directly with your package manager. See Quick Start and the per‑command pages under CLI.
-### How is Better-T-Stack different from other scaffolding tools?
+### Which package manager can I use?
+`npm`, `pnpm`, or `bun` (all supported).
-- **End-to-End Type Safety**: TypeScript across your entire stack with proper type sharing
-- **Modern Stack Focus**: Latest versions of popular frameworks and tools
-- **Production Ready**: Configurations used in real production applications
-- **Highly Customizable**: Mix and match technologies based on your needs
-- **Monorepo Structure**: Organized project structure with shared packages
-- **Database Integration**: Built-in database setup and ORM configuration
-- **Authentication**: Integrated auth with Better-Auth
-- **Multi-Platform**: Web, mobile, and desktop app support in one project
+### What Node.js version is required?
+Node.js 18+ (LTS recommended).
-### Is Better-T-Stack free to use?
+### Can I use this with an existing project?
+The CLI is for new projects. You can migrate gradually or use `add` to extend a Better‑T‑Stack project.
-Yes, Better-T-Stack is completely free and open-source under the MIT license. You can use it for personal and commercial projects without any restrictions.
+### Where do generated files live?
+See Project Structure for high‑level layouts (server‑based vs. Convex, optional web/native).
-### Do I need to know all these technologies to use Better-T-Stack?
+## Choosing options
-No! Better-T-Stack is designed to help you learn modern full-stack development. Each generated project includes:
-- Comprehensive README with setup instructions
-- Example code and patterns
-- TypeScript for better developer experience
-- Best practices and folder structure
+### Does the CLI recommend a stack?
+No. Pick what fits your needs. The CLI validates compatibility. See CLI (per command) and Compatibility for rules.
----
-
-## Installation & Setup
-
-### Which package manager should I use?
-
-You can use any of the major package managers:
-- **npm**: Most widely supported, comes with Node.js
-- **pnpm**: Faster installs, better disk space efficiency
-- **bun**: All-in-one runtime, extremely fast
-
-For monorepo projects, we recommend **pnpm** for its excellent workspace support.
-
-### Do I need to install the CLI globally?
-
-No, you can use npx to run the latest version without installation:
-
-```bash
-npx create-better-t-stack@latest my-project
-```
-
-This ensures you always use the latest version with the newest features and bug fixes.
-
-### What Node.js version do I need?
-
-Better-T-Stack requires **Node.js 18 or higher**. We recommend using the latest LTS version for the best experience.
-
-### Can I use Better-T-Stack with existing projects?
-
-Better-T-Stack is designed for new projects. For existing projects, you can:
-1. Create a new Better-T-Stack project
-2. Gradually migrate your code
-3. Use the `add` command to add specific features to existing Better-T-Stack projects
-
----
-
-## Configuration & Stack Choices
-
-### Can I change my stack choices after creating a project?
-
-Some changes are possible:
-- **Easy**: Add addons, examples, or deployment configurations using the `add` command
-- **Medium**: Switch between compatible ORMs or databases (requires manual migration)
-- **Hard**: Change frontend/backend frameworks (requires significant refactoring)
-
-It's best to plan your stack carefully during initial setup.
-
-### What's the difference between tRPC and oRPC?
-
-- **tRPC**: End-to-end type safety with TypeScript inference, great for TypeScript-only projects
-- **oRPC**: OpenAPI-compatible type-safe APIs, better for teams using multiple languages or requiring OpenAPI specs
-
-Both provide excellent type safety, choose based on your team's needs.
-
-### Should I use Drizzle or Prisma?
-
-- **Drizzle**: TypeScript-first, lightweight, great for edge deployments, SQL-like syntax
-- **Prisma**: Feature-rich, mature ecosystem, great tooling, GraphQL-like schema
-
-Choose Drizzle for modern TypeScript projects and Prisma for feature-rich applications.
-
-### What's the recommended stack for beginners?
-
-For beginners, we recommend:
-```bash
-npx create-better-t-stack@latest my-first-project \
- --frontend tanstack-router \
- --backend hono \
- --database sqlite \
- --orm drizzle \
- --auth \
- --addons turborepo biome
-```
-
-This provides a simple but powerful full-stack setup that's easy to understand and deploy.
-
----
-
-## Compatibility Questions
-
-### Can I use MongoDB with Drizzle?
-
-No, Drizzle doesn't support MongoDB. For MongoDB, use:
-- **Prisma ORM**: Full ORM support for MongoDB
-- **Mongoose**: Traditional MongoDB object modeling
-
-### Why can't I use tRPC with Nuxt/SvelteKit/SolidJS?
-
-tRPC is primarily designed for React ecosystems. For these frameworks, use:
-- **oRPC**: Provides similar type safety with broader framework support
-- **None**: Use the framework's built-in API capabilities
-
-### Can I use Cloudflare Workers with any backend?
-
-Cloudflare Workers runtime only supports:
-- **Backend**: Hono only
-- **Database**: SQLite with Cloudflare D1
-- **ORM**: Drizzle only
-
-This is due to the serverless nature and limitations of the Workers environment.
-
-### Which addons work with which frontends?
-
-| Addon | Compatible Frontends |
-|-------|---------------------|
-| PWA | TanStack Router, React Router, SolidJS, Next.js |
-| Tauri | TanStack Router, React Router, Nuxt, SvelteKit, SolidJS, Next.js |
-| Turborepo | All frontends |
-| Biome | All frontends |
-| Husky | All frontends |
-| Starlight | All frontends |
-
----
-
-## Database & Hosting
-
-### What database should I choose for production?
-
-**For small to medium applications:**
-- **SQLite + Turso**: Excellent performance, easy scaling
-- **PostgreSQL + Neon**: Serverless PostgreSQL, great for startups
-
-**For large applications:**
-- **PostgreSQL + Supabase**: Full backend-as-a-service
-- **MongoDB + Atlas**: NoSQL flexibility with managed hosting
-
-### Do I need Docker for development?
-
-Docker is optional and only required for:
-- **Database Setup**: If you choose `--db-setup docker`
-- **Local Development**: Some setups like Supabase local development
-
-Many database options (Turso, Neon, MongoDB Atlas) don't require Docker.
-
-### How do I deploy my Better-T-Stack application?
-
-Better-T-Stack projects are configured for easy deployment:
+### I’m unsure between tRPC and oRPC / Drizzle and Prisma
+See Compatibility for guidance and constraints. Both pairs work well; choose based on team and hosting needs.
-**Frontend:**
-- **Vercel**: Zero-config deployment for Next.js, React apps
-- **Netlify**: Static site deployment
-- **Cloudflare Workers**: Edge deployment with `--web-deploy workers`
+## Common issues
-**Backend:**
-- **Railway**: Easy backend deployment
-- **Fly.io**: Global application deployment
-- **Cloudflare Workers**: Serverless edge deployment
-
----
-
-## Development & Troubleshooting
-
-### My project won't start after creation. What should I do?
-
-1. **Check Node.js version**: Ensure you're using Node.js 18+
-2. **Install dependencies**: Run `npm install` in the project directory
-3. **Check environment variables**: Copy `.env.example` to `.env` and fill in values
-4. **Database setup**: Run database migrations if using a database
-5. **Check the README**: Each project includes detailed setup instructions
-
-### I'm getting TypeScript errors. How do I fix them?
-
-1. **Install dependencies**: Ensure all packages are installed
-2. **Restart TypeScript server**: In VS Code, use Ctrl/Cmd + Shift + P → "TypeScript: Restart TS Server"
-3. **Check imports**: Ensure all imports are correct and packages are installed
-4. **Update types**: Run `npm run check-types` to see detailed errors
-
-### How do I update dependencies in my project?
-
-```bash
-# Check for updates
-npx taze -r
-
-# Update all dependencies
-npm update
-
-# Or with other package managers
-pnpm update
-bun update
-```
-
-### Can I use Better-T-Stack with VS Code?
-
-Yes! Better-T-Stack projects work excellently with VS Code. We recommend these extensions:
-- TypeScript and JavaScript Language Features (built-in)
-- Tailwind CSS IntelliSense
-- Prisma or Drizzle Kit extensions
-- ESLint (if using Biome addon)
-
-### My mobile app won't connect to the backend. What's wrong?
-
-This is a common issue with Expo and local development:
-
-1. **Check environment variables**: Update `EXPO_PUBLIC_SERVER_URL` in `apps/native/.env`
-2. **Use your local IP**: Replace `localhost` with your computer's IP address
-3. **Check firewall**: Ensure your firewall allows connections on port 3000
-4. **Use tunnel**: Consider using `npx expo start --tunnel`
-
----
-
-## Advanced Usage
-
-### Can I customize the generated templates?
-
-Currently, Better-T-Stack doesn't support custom templates, but you can:
-1. Fork the repository and modify templates
-2. Create a feature request for specific customizations
-3. Modify the generated project after creation
-
-### How do I contribute to Better-T-Stack?
-
-We welcome contributions! Here's how to get started:
-
-1. **Fork the repository** on GitHub
-2. **Clone your fork** locally
-3. **Install dependencies**: `pnpm install`
-4. **Make your changes** and test them
-5. **Submit a pull request** with a clear description
-
-### Can I use Better-T-Stack in my company/team?
-
-Absolutely! Better-T-Stack is perfect for:
-- **Standardizing project structure** across teams
-- **Onboarding new developers** with consistent setup
-- **Rapid prototyping** and MVP development
-- **Client projects** with proven, production-ready configurations
+### My mobile app can’t connect to the backend (Expo)
+Set `EXPO_PUBLIC_SERVER_URL` in `apps/native/.env` to your machine IP (not `localhost`), check firewall, or try `npx expo start --tunnel`.
### How do I disable telemetry?
+Set `BTS_TELEMETRY_DISABLED=1` (shell env). For one run, prefix the command; to make it permanent, export it in your shell profile.
-Better-T-Stack collects anonymous usage data to improve the tool. To disable:
-
-```bash
-# Disable for single run
-BTS_TELEMETRY_DISABLED=1 npx create-better-t-stack@latest my-app
-
-# Disable globally
-export BTS_TELEMETRY_DISABLED=1
-```
-
-Add the export to your shell profile (`.bashrc`, `.zshrc`, etc.) to make it permanent.
-
----
-
-## Getting Help
-
-### Where can I get help?
-
-- **Documentation**: Comprehensive guides at [better-t-stack.dev/docs](https://better-t-stack.dev/docs)
-- **GitHub Issues**: Report bugs or request features
-- **GitHub Discussions**: Community support and questions
-- **Discord/Twitter**: Follow for updates and community discussion
-
-### How do I report a bug?
-
-1. **Search existing issues** to avoid duplicates
-2. **Create a new issue** with:
- - Clear description of the problem
- - Steps to reproduce
- - Your system information (OS, Node.js version, etc.)
- - Generated project configuration
- - Error messages or screenshots
-
-### How do I request a new feature?
-
-1. **Check existing feature requests** in GitHub Issues
-2. **Create a new issue** with the "feature request" label
-3. **Describe the feature** and its use case
-4. **Explain why** it would benefit the community
-
-### Is there a community?
-
-Yes! You can connect with other Better-T-Stack users:
-- **GitHub Discussions**: Ask questions and share projects
-- **Twitter**: Follow [@AmanVarshney01](https://twitter.com/AmanVarshney01) for updates
-- **Show your projects**: Tag us when you build something with Better-T-Stack!
-
----
-
-## Sponsorship & Support
-
-### How can I support Better-T-Stack?
-
-- **⭐ Star the repository** on GitHub
-- **🐛 Report bugs** and suggest improvements
-- **💰 Sponsor the project** on GitHub Sponsors
-- **📢 Share with others** who might find it useful
-- **🤝 Contribute code** or documentation
-
-### Who sponsors Better-T-Stack?
-
-View current sponsors by running:
-```bash
-npx create-better-t-stack@latest sponsors
-```
-
-Or visit: [github.com/sponsors/AmanVarshney01](https://github.com/sponsors/AmanVarshney01)
-
----
+## Getting help
-*Still have questions? Feel free to ask in [GitHub Discussions](https://github.com/AmanVarshney01/create-better-t-stack/discussions) or check our [documentation](https://better-t-stack.dev/docs).*
+- Docs: Quick Start, CLI, Project Structure, Compatibility
+- Ask/Report: GitHub Issues & Discussions
+- Community: Discord
diff --git a/apps/web/content/docs/index.mdx b/apps/web/content/docs/index.mdx
index 45d9571e..81314765 100644
--- a/apps/web/content/docs/index.mdx
+++ b/apps/web/content/docs/index.mdx
@@ -1,118 +1,278 @@
---
-title: Getting Started
-description: A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations
+title: Quick Start
+description: Create your first Better-T-Stack project in minutes
---
-> ⚠️ **Warning:** Documentation is a work in progress.
+## Philosophy
-## What is Better-T-Stack?
+- Roll your own stack: pick only what you need, nothing extra.
+- Minimal templates: bare-bones scaffolds with zero bloat.
+- Latest dependencies: always current and stable by default.
+- Free and open source: forever.
-Better-T-Stack is designed to eliminate the complexity of setting up modern TypeScript projects. Instead of spending hours configuring build tools, type systems, databases, and deployment pipelines, you can get a production-ready project structure in minutes.
+## Get Started
-### Key Features
+### CLI (prompts)
-- **🏗️ Full-Stack Ready**: Choose from multiple frontend and backend frameworks
-- **🔒 End-to-End Type Safety**: TypeScript across your entire application stack
-- **🗄️ Database Integration**: Support for SQLite, PostgreSQL, MySQL, and MongoDB
-- **🔐 Built-in Authentication**: Email/password auth with Better-Auth
-- **📱 Multi-Platform**: Web, mobile (React Native), and desktop (Tauri) support
-- **☁️ Deployment Ready**: Configured for modern hosting platforms
-- **⚡ Modern Tooling**: Latest versions of your favorite tools and frameworks
+
+
+ ```bash
+ bun create better-t-stack@latest
+ ```
+
+
+ ```bash
+ pnpm create better-t-stack@latest
+ ```
+
+
+ ```bash
+ npx create-better-t-stack@latest
+ ```
+
+
-### Supported Technologies
+Follow the interactive prompts to choose your frontend, backend, database, ORM, API layer, and addons.
-#### Frontend Frameworks
-- **React** with TanStack Router or React Router
-- **Next.js** - Full-stack React framework
-- **SvelteKit** - Web framework for Svelte
-- **Nuxt** - Vue.js framework
-- **SolidJS** - Performant reactive framework
-- **TanStack Start** - SSR with TanStack Router
-- **React Native** - Mobile development with Expo
+Skip prompts and use the default stack:
-#### Backend Frameworks
-- **Hono** - Lightweight, ultrafast web framework
-- **Express** - Popular Node.js framework
-- **Fastify** - Fast, low-overhead framework
-- **Elysia** - Type-safe, high-performance framework
-- **Convex** - Reactive backend-as-a-service
-- **Next.js API Routes** - Full-stack React
+
+
+ ```bash
+ bun create better-t-stack@latest my-app --yes
+ ```
+
+
+ ```bash
+ pnpm create better-t-stack@latest my-app --yes
+ ```
+
+
+ ```bash
+ npx create-better-t-stack@latest my-app --yes
+ ```
+
+
-#### Databases & ORMs
-- **Databases**: SQLite/Turso, PostgreSQL, MySQL, MongoDB
-- **ORMs**: Drizzle (TypeScript-first), Prisma (feature-rich), Mongoose
-- **Hosting**: Neon, Supabase, MongoDB Atlas, Cloudflare D1
+
-#### API Layers
-- **tRPC** - End-to-end type-safe APIs
-- **oRPC** - OpenAPI-compatible type-safe APIs
+### Stack Builder (UI)
-### Why Choose Better-T-Stack?
+- Visit [/new](/new) to pick your stack and copy the generated command
+- Or open it via:
-#### Traditional Setup Problems
-- ⏰ Hours of configuration and setup
-- 🔧 Complex toolchain integration
-- 📚 Overwhelming technology choices
-- 🐛 Configuration bugs and compatibility issues
-- 🏗️ Inconsistent project structures
+
+
+ ```bash
+ bun create better-t-stack@latest builder
+ ```
+
+
+ ```bash
+ pnpm create better-t-stack@latest builder
+ ```
+
+
+ ```bash
+ npx create-better-t-stack@latest builder
+ ```
+
+
-#### Better-T-Stack Solutions
-- ⚡ **Quick Setup**: Get started in under 2 minutes
-- 🎯 **Curated Choices**: Pre-selected, compatible technology combinations
-- 📋 **Best Practices**: Industry-standard configurations out of the box
-- 🔄 **Consistent Structure**: Standardized monorepo organization
-- 🧪 **Battle-Tested**: Configurations used in production applications
+## Common Setups
-## Quick Example
+### Default Stack
-```bash
-# Create a new project
-npx create-better-t-stack@latest my-app
+
+
+ ```bash
+ bun create better-t-stack@latest my-webapp \
+ --frontend tanstack-router \
+ --backend hono \
+ --database sqlite \
+ --orm drizzle \
+ --auth \
+ --addons turborepo
+ ```
+
+
+ ```bash
+ pnpm create better-t-stack@latest my-webapp \
+ --frontend tanstack-router \
+ --backend hono \
+ --database sqlite \
+ --orm drizzle \
+ --auth \
+ --addons turborepo
+ ```
+
+
+ ```bash
+ npx create-better-t-stack@latest my-webapp \
+ --frontend tanstack-router \
+ --backend hono \
+ --database sqlite \
+ --orm drizzle \
+ --auth \
+ --addons turborepo
+ ```
+
+
-# Choose your stack interactively or use flags
-npx create-better-t-stack@latest my-app \
- --frontend tanstack-router \
- --backend hono \
- --database postgres \
- --orm drizzle \
- --auth \
- --addons pwa turborepo
-```
+### Convex + React
-## Project Types
+
+
+ ```bash
+ bun create better-t-stack@latest my-convex-app \
+ --frontend tanstack-router \
+ --backend convex
+ ```
+
+
+ ```bash
+ pnpm create better-t-stack@latest my-convex-app \
+ --frontend tanstack-router \
+ --backend convex
+ ```
+
+
+ ```bash
+ npx create-better-t-stack@latest my-convex-app \
+ --frontend tanstack-router \
+ --backend convex
+ ```
+
+
-Better-T-Stack supports various project configurations:
+### API Only
-### Full-Stack Web Applications
-Perfect for modern web apps with React, Vue, or Svelte frontends backed by type-safe APIs.
+
+
+ ```bash
+ bun create better-t-stack@latest my-api \
+ --frontend none \
+ --backend fastify \
+ --runtime node \
+ --database postgres \
+ --orm prisma \
+ --api trpc
+ ```
+
+
+ ```bash
+ pnpm create better-t-stack@latest my-api \
+ --frontend none \
+ --backend fastify \
+ --runtime node \
+ --database postgres \
+ --orm prisma \
+ --api trpc
+ ```
+
+
+ ```bash
+ npx create-better-t-stack@latest my-api \
+ --frontend none \
+ --backend fastify \
+ --runtime node \
+ --database postgres \
+ --orm prisma \
+ --api trpc
+ ```
+
+
-### Mobile Applications
-Build React Native apps with Expo, sharing type definitions with your backend.
+### Mobile App (Expo)
-### Desktop Applications
-Create cross-platform desktop apps using Tauri with your web frontend.
+
+
+ ```bash
+ bun create better-t-stack@latest my-native \
+ --frontend native-nativewind \
+ --backend hono \
+ --database sqlite \
+ --orm drizzle \
+ --auth
+ ```
+
+
+ ```bash
+ pnpm create better-t-stack@latest my-native \
+ --frontend native-nativewind \
+ --backend hono \
+ --database sqlite \
+ --orm drizzle \
+ --auth
+ ```
+
+
+ ```bash
+ npx create-better-t-stack@latest my-native \
+ --frontend native-nativewind \
+ --backend hono \
+ --database sqlite \
+ --orm drizzle \
+ --auth
+ ```
+
+
-### API-Only Projects
-Build standalone APIs and microservices with your preferred backend framework.
+### Empty Monorepo
-### Monorepo Projects
-Organize multiple applications (web, mobile, API) in a single repository with shared packages.
+
+
+ ```bash
+ bun create better-t-stack@latest my-workspace \
+ --frontend none \
+ --backend none
+ ```
+
+
+ ```bash
+ pnpm create better-t-stack@latest my-workspace \
+ --frontend none \
+ --backend none
+ ```
+
+
+ ```bash
+ npx create-better-t-stack@latest my-workspace \
+ --frontend none \
+ --backend none
+ ```
+
+
-## Who Should Use Better-T-Stack?
+## Flags Cheat Sheet
-- **Indie Developers**: Quickly prototype and build full-stack applications
-- **Startups**: Get to market faster with production-ready project structure
-- **Teams**: Standardize project setup across your organization
-- **Students**: Learn modern full-stack development with best practices
-- **Agencies**: Rapidly scaffold client projects with consistent quality
+See the full list in the [CLI Reference](/docs/cli). Key flags:
-## What's Next?
-
-Ready to get started? Check out our [Quick Start Guide](/docs/quick-start) to create your first Better-T-Stack project, or explore the [Configuration Options](/docs/frontend) to learn about all available technologies and features.
-
-### Need Help?
-
-- 📖 **Documentation**: Comprehensive guides and references
-- 🐛 **Issues**: Report bugs on [GitHub](https://github.com/AmanVarshney01/create-better-t-stack/issues)
-- 💬 **Discussions**: Community support and questions
-- 🌟 **Star us**: Show support on [GitHub](https://github.com/AmanVarshney01/create-better-t-stack)
+- `--frontend`: tanstack-router, react-router, tanstack-start, next, nuxt, svelte, solid, native-nativewind, native-unistyles, none
+- `--backend`: hono, express, fastify, elysia, next, convex, none
+- `--runtime`: bun, node, workers, none
+- `--database`: sqlite, postgres, mysql, mongodb, none
+- `--orm`: drizzle, prisma, mongoose, none
+- `--api`: trpc, orpc, none
+- `--addons`: turborepo, pwa, tauri, biome, husky, starlight, none
+- `--examples`: todo, ai, none
+
+## Next Steps
+
+
+
+ Flags, usage, and examples for each command
+
+
+ See how web/server/native and Convex layouts are generated
+
+
+ Valid combinations for backend, runtime, database, ORM, API
+
+
+ Required for the add command; safe to delete if you don’t use add
+
+
+ Dev setup and contribution flow
+
+
diff --git a/apps/web/content/docs/installation.mdx b/apps/web/content/docs/installation.mdx
deleted file mode 100644
index 0dc06be2..00000000
--- a/apps/web/content/docs/installation.mdx
+++ /dev/null
@@ -1,236 +0,0 @@
----
-title: Installation
-description: How to install and set up Better-T-Stack CLI
----
-
-## System Requirements
-
-Before installing Better-T-Stack, ensure your system meets these requirements:
-
-- **Node.js**: Version 18 or higher
-- **Package Manager**: npm, pnpm, or bun
-- **Git**: For repository initialization (optional but recommended)
-
-### Optional Dependencies
-
-Depending on your project configuration, you may need:
-
-- **Docker**: For local database development with Docker Compose
-- **Rust & System Dependencies**: For Tauri desktop applications
-- **Cloudflare CLI**: For Workers deployment
-
-## Quick Start (Recommended)
-
-The fastest way to get started is using npx, which runs the latest version without installation:
-
-```bash
-npx create-better-t-stack@latest my-project
-```
-
-This command will:
-1. Download the latest version of the CLI
-2. Run the interactive setup wizard
-3. Create your project in the `my-project` directory
-
-## Package Manager Specific Commands
-
-### npm
-
-```bash
-# Run without installing
-npx create-better-t-stack@latest my-project
-
-# Or install globally
-npm install -g create-better-t-stack
-create-better-t-stack my-project
-```
-
-### pnpm
-
-```bash
-# Run without installing (recommended)
-pnpm create better-t-stack@latest my-project
-
-# Or install globally
-pnpm add -g create-better-t-stack
-create-better-t-stack my-project
-```
-
-### bun
-
-```bash
-# Run without installing (recommended)
-bun create better-t-stack@latest my-project
-
-# Or install globally
-bun add -g create-better-t-stack
-create-better-t-stack my-project
-```
-
-## Global Installation
-
-If you frequently create new projects, you might want to install the CLI globally:
-
-
-
- ```bash
- npm install -g create-better-t-stack
- ```
-
-
- ```bash
- pnpm add -g create-better-t-stack
- ```
-
-
- ```bash
- bun add -g create-better-t-stack
- ```
-
-
-
-After global installation, you can run:
-
-```bash
-create-better-t-stack my-project
-```
-
-## Verification
-
-Verify your installation by checking the version:
-
-```bash
-# If installed globally
-create-better-t-stack --version
-
-# Or with npx
-npx create-better-t-stack@latest --version
-```
-
-You should see output similar to:
-
-```
-2.26.3
-```
-
-## Development Installation
-
-For contributing to Better-T-Stack or running the latest development version:
-
-```bash
-# Clone the repository
-git clone https://github.com/AmanVarshney01/create-better-t-stack.git
-cd create-better-t-stack
-
-# Install dependencies
-pnpm install
-
-# Build the CLI
-cd apps/cli
-pnpm build
-
-# Link for local development
-pnpm link --global
-```
-
-## Troubleshooting
-
-### Common Issues
-
-#### Permission Errors (npm)
-
-If you encounter permission errors with npm global installation:
-
-```bash
-# Use npx instead (recommended)
-npx create-better-t-stack@latest my-project
-
-# Or configure npm to use a different directory
-mkdir ~/.npm-global
-npm config set prefix '~/.npm-global'
-echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
-source ~/.bashrc
-```
-
-#### Node.js Version Issues
-
-Ensure you're using Node.js 18 or higher:
-
-```bash
-node --version
-```
-
-If you need to upgrade Node.js:
-
-- **Using nvm**: `nvm install 18 && nvm use 18`
-- **Using n**: `n 18`
-- **Download**: Visit [nodejs.org](https://nodejs.org/)
-
-#### Package Manager Not Found
-
-If you prefer a specific package manager but it's not installed:
-
-```bash
-# Install pnpm
-npm install -g pnpm
-
-# Install bun
-curl -fsSL https://bun.sh/install | bash
-```
-
-#### Network Issues
-
-If you experience network timeouts or connection issues:
-
-```bash
-# Try with different registry
-npm config set registry https://registry.npmjs.org/
-
-# Or clear npm cache
-npm cache clean --force
-```
-
-## Next Steps
-
-Once installed, you're ready to create your first project:
-
-1. **Quick Start**: Follow our [Quick Start Guide](/docs/quick-start)
-2. **Configuration**: Learn about [Configuration Options](/docs/frontend)
-3. **CLI Reference**: Explore all [CLI Commands](/docs/cli-commands)
-
-## Staying Updated
-
-To ensure you're always using the latest version with bug fixes and new features:
-
-### Using npx (Automatic)
-When using `npx create-better-t-stack@latest`, you automatically get the latest version.
-
-### Global Installation Updates
-
-If you have it installed globally, update regularly:
-
-
-
- ```bash
- npm update -g create-better-t-stack
- ```
-
-
- ```bash
- pnpm update -g create-better-t-stack
- ```
-
-
- ```bash
- bun update -g create-better-t-stack
- ```
-
-
-
-### Release Notes
-
-Stay informed about new features and changes:
-
-- **GitHub Releases**: [View releases](https://github.com/AmanVarshney01/create-better-t-stack/releases)
-- **Changelog**: Check the repository for detailed changes
-- **Breaking Changes**: Major version updates may include breaking changes
diff --git a/apps/web/content/docs/meta.json b/apps/web/content/docs/meta.json
index 1b834409..0753258c 100644
--- a/apps/web/content/docs/meta.json
+++ b/apps/web/content/docs/meta.json
@@ -1,32 +1,12 @@
{
"pages": [
"index",
- "installation",
- "quick-start",
+ "cli",
"project-structure",
- "---Configuration Options---",
- "frontend",
- "backend",
- "database",
- "orm",
- "authentication",
- "runtime",
- "api-layer",
- "---Addons & Features---",
- "addons",
- "examples",
- "deployment",
- "---Database Setup---",
- "database-providers",
- "---CLI Reference---",
- "cli-commands",
- "cli-flags",
- "---Guides---",
- "migration-guide",
- "troubleshooting",
- "best-practices",
- "---FAQ---",
- "faq",
- "compatibility"
+ "bts-config",
+ "analytics",
+ "contributing",
+ "compatibility",
+ "faq"
]
}
diff --git a/apps/web/content/docs/project-structure.mdx b/apps/web/content/docs/project-structure.mdx
new file mode 100644
index 00000000..466dbc70
--- /dev/null
+++ b/apps/web/content/docs/project-structure.mdx
@@ -0,0 +1,60 @@
+---
+title: Project Structure
+description: High-level overview of the generated monorepo layout
+---
+
+import { File, Folder, Files } from 'fumadocs-ui/components/files';
+
+### Server-based projects
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Notes:
+- `apps/server` is present for backends like `hono`, `express`, `fastify`, `elysia`, `next`.
+- `apps/web` and `apps/native` are optional; they appear only if you select a web or native frontend.
+
+### Convex-based projects
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Notes:
+- Convex replaces the server app; `packages/backend` is generated instead of `apps/server`.
+- Auth, DB/ORM, and API scaffolding are disabled for Convex presets.
+
+### Where features land (high level)
+
+- API layer: merged into `apps/server` and `apps/web` when applicable.
+- Database & ORM: merged into `apps/server` when both are selected.
+- Authentication: merged into `apps/server`, `apps/web`, and `apps/native` when enabled and compatible.
+- Addons: PWA merges into `apps/web`; others merge at the appropriate location.
+- Web deployment (Workers): deployment files merge into `apps/web` per frontend.
+- Runtime extras (Workers): Workers-specific files added at the repo root.
+
diff --git a/apps/web/src/app/(home)/_components/footer.tsx b/apps/web/src/app/(home)/_components/footer.tsx
index bfa46514..fa6ee508 100644
--- a/apps/web/src/app/(home)/_components/footer.tsx
+++ b/apps/web/src/app/(home)/_components/footer.tsx
@@ -18,7 +18,7 @@ const Footer = () => {
{
GitHub Repository
diff --git a/apps/web/src/app/(home)/_components/navbar.tsx b/apps/web/src/app/(home)/_components/navbar.tsx
index a0780d09..2794f18f 100644
--- a/apps/web/src/app/(home)/_components/navbar.tsx
+++ b/apps/web/src/app/(home)/_components/navbar.tsx
@@ -85,7 +85,7 @@ export default function Navbar() {
target: "_blank",
},
{
- href: "https://www.github.com/better-t-stack/create-better-t-stack",
+ href: "https://www.github.com/AmanVarshney01/create-better-t-stack",
label: "GitHub",
icon: ,
target: "_blank",
diff --git a/apps/web/src/app/(home)/analytics/_components/analytics-header.tsx b/apps/web/src/app/(home)/analytics/_components/analytics-header.tsx
index 9abfa284..6d605492 100644
--- a/apps/web/src/app/(home)/analytics/_components/analytics-header.tsx
+++ b/apps/web/src/app/(home)/analytics/_components/analytics-header.tsx
@@ -48,7 +48,7 @@ export function AnalyticsHeader({
Source:{" "}
-
- ⚠️ WORK IN PROGRESS DONT TAKE REFERENCE!!!
-
- {children}
- >
- );
+ return {children};
}
diff --git a/bun.lock b/bun.lock
index 82ee4837..d4278b0d 100644
--- a/bun.lock
+++ b/bun.lock
@@ -14,7 +14,7 @@
},
"apps/cli": {
"name": "create-better-t-stack",
- "version": "2.29.2",
+ "version": "2.29.3",
"bin": {
"create-better-t-stack": "dist/index.js",
},