# fullstack-starter Opinionated single-binary fullstack starter. Bun + TanStack Start (React 19 SSR) + ORPC (contract-first) + Drizzle + PostgreSQL, deployed as one compiled executable. > Agent notes and non-obvious invariants live in [AGENTS.md](./AGENTS.md). Read it before making structural changes. ## Quick start ```bash cp .env.example .env bun install bun run db:push # dev: sync schema without migration files bun run dev # http://localhost:3000 ``` RPC endpoint: `/api/rpc` · OpenAPI docs: `/api/docs` · Spec: `/api/spec.json` · Liveness: `/health`. ## Scripts | Command | What it does | | --- | --- | | `bun run dev` | Vite dev server on port 3000 (strict) | | `bun run build` | Build to `.output/` | | `bun run compile` | Single-binary `out/server-` via `bun build --compile` | | `bun run cli ` | Run a CLI subcommand in source (`serve`, `migrate`) | | `bun run typecheck` | `tsc --noEmit` | | `bun run test` | `bun test` (colocated `*.test.ts`) | | `bun run fix` | Biome lint + format + organize imports | | `bun run db:push` | Dev-only schema sync (no migration files) | | `bun run db:generate` | Write SQL migrations to `./drizzle` and regenerate `migrations.gen.ts` | | `bun run db:embed` | Regenerate `src/server/db/migrations.gen.ts` from `./drizzle` (run if you hand-edit migrations) | | `bun run db:migrate` | Apply migrations locally via drizzle-kit (dev convenience) | | `bun run db:studio` | Drizzle Studio | Cross-compile: `bun run compile:{linux,darwin,windows}[:arch]`. ## Add a feature (e.g. `post`) Contract-first, additive. Create or touch files in this order: 1. `src/server/db/schema/post.ts` — define `postTable`, spread `...generatedFields`. 2. `src/server/db/schema/index.ts` — `export * from './post'`. 3. `src/server/api/contracts/post.contract.ts` — derive Zod from the table via `drizzle-zod`. 4. `src/server/api/contracts/index.ts` — add `post` to the `contract` object. 5. `src/server/api/routers/post.router.ts` — implement `os.post.*.handler(...)`. 6. `src/server/api/routers/index.ts` — add `post` to the `router` object. 7. `src/client/queries/post.ts` — export `useInvalidatePosts` (or finer-grained helpers) for affected list keys. 8. `src/routes/.tsx` — UI with `useSuspenseQuery` + loader `ensureQueryData`; call the helper from mutation `onSuccess`. 9. `bun run db:generate` — emit SQL migrations to `./drizzle` and embed them into `src/server/db/migrations.gen.ts`. ## Deploy Always **migrate-then-serve**. Migrations are embedded in the binary; the binary is the only artifact you ship. ```bash ./server migrate # applies embedded migrations against $DATABASE_URL ./server # starts HTTP server (default subcommand) ``` `compose.yaml` models the pattern with a one-shot `migrate` service that `app` depends on (`service_completed_successfully`). On Kubernetes: run `./server migrate` as an initContainer or Helm `pre-upgrade` Job. ```bash docker compose up --build ```