Turborepo monorepo with:
apps/web— Next.js 15 (App Router, Turbopack, Tailwind v4, shadcn/ui)apps/database— Drizzle ORM + PostgreSQLbackends/fastapi— FastAPI (Python 3.12, uv)
Always use bun. Never use npm, yarn, or pnpm.
bun install # install deps
bun add <pkg> # add a dep
bun add -d <pkg> # add a dev dep
bunx <tool> # run a package binaryAlways use Biome. Never add ESLint or Prettier.
bun run check # lint + format (auto-fix)
bun run format # format onlyAlways use ~/src/env.ts (T3 env) to access environment variables inside apps/web.
Never use process.env.* directly in Next.js application code.
-
Add it to
apps/web/src/env.ts:- Server-only (no browser access) → goes in the
server:block - Client-side (must start with
NEXT_PUBLIC_) → goes in theclient:block - Add a matching entry in
runtimeEnv:pointing toprocess.env.VAR_NAME
- Server-only (no browser access) → goes in the
-
Add it to
apps/web/.env.local.exampleand to the root.env.example -
Add it to your local
apps/web/.env.local
// ✅ Correct
import { env } from "~/env";
const url = env.DATABASE_URL; // server component / API route
const api = env.NEXT_PUBLIC_API_URL; // any component
// ❌ Wrong — never do this inside apps/web
const url = process.env.DATABASE_URL;apps/database/src/db.ts and apps/database/drizzle.config.ts are CLI/server-only
utilities — they may use process.env directly since they are not Next.js modules.
Use shadcn/ui for all UI components.
# Add a new shadcn component (run from apps/web)
bunx shadcn@latest add <component-name>Components are placed in apps/web/src/components/ui/.
The cn() helper for class merging is at apps/web/src/lib/utils.ts.
bun run db:up # start Postgres (Docker)
bun run db:push # push schema changes (dev)
bun run db:generate # generate SQL migration files
bun run db:migrate # apply migrations
bun run db:studio # open Drizzle StudioSchema lives in apps/database/src/schema/index.ts.
bun run dev # start all services (TUI)
bun run build # build all packages
bun run lint # lint all packages