src/cli/_serve-nitro.mjs 原本用 ../../.output/server/index.mjs 跨边界导入 nitro 构建产物,与 #package / #drizzle/* 同属 "src/ 跳出根目录" 场景。统一改为 #nitro。 新增 package.json#imports: "#nitro": "./.output/server/index.mjs" 端到端验证(compose + Postgres 18): - 编译二进制内嵌 nitro serve() 入口 ✓ - ./server migrate:embedded SQL 应用成功 ✓ - ./server 运行:/health、/api/spec.json (title/version)、RPC create+list 全 OK ✓ - Stack trace 印证 #nitro 由 Bun 正确解析到 .output/server/index.mjs ✓ - biome/typecheck/test/build/compile 全绿
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. Read it before making structural changes.
Quick start
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-<target> via bun build --compile |
bun run cli <cmd> |
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:
src/server/db/schema/post.ts— definepostTable, spread...generatedFields.src/server/db/schema/index.ts—export * from './post'.src/server/api/contracts/post.contract.ts— derive Zod from the table viadrizzle-zod.src/server/api/contracts/index.ts— addpostto thecontractobject.src/server/api/routers/post.router.ts— implementos.post.*.handler(...).src/server/api/routers/index.ts— addpostto therouterobject.src/client/queries/post.ts— exportuseInvalidatePosts(or finer-grained helpers) for affected list keys.src/routes/<page>.tsx— UI withuseSuspenseQuery+ loaderensureQueryData; call the helper from mutationonSuccess.bun run db:generate— emit SQL migrations to./drizzleand embed them intosrc/server/db/migrations.gen.ts.
Deploy
Always migrate-then-serve. Migrations are embedded in the binary; the binary is the only artifact you ship.
./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.
docker compose up --build