A pnpm + Turborepo scaffold for building a small full-stack TypeScript app with:
- a Next.js frontend (
apps/web) - an Express API (
apps/api) - a shared Prisma DB package (
packages/db) - shared validation/schema types (
packages/schema) - a shared UI component package (
packages/ui)
To use, run:
pnpm dlx degit lmulvey/skelly my-app
This setup is optimized for quickly building product ideas while keeping boundaries clean:
- Apps stay thin and focus on runtime behavior.
- Domain concerns are shared (
@repo/schema,@repo/db,@repo/ui) to avoid copy/paste drift. - Tooling is centralized (
@repo/biome-config,@repo/typescript-config,@repo/tailwind-config) so standards are consistent everywhere. - Turbo caching + task graph keeps local and CI runs fast as the workspace grows.
apps/web— Next.js app router frontend- Uses
@repo/uicomponents and@repo/tailwind-configstyles. - Imports shared UI CSS from
@repo/ui/styles.cssinapp/globals.css.
- Uses
apps/api— Express API (TypeScript)- Exposes
/healthand/itemsCRUD routes. - Uses
@repo/schemafor Zod validation and@repo/dbfor Prisma access.
- Exposes
-
packages/ui(@repo/ui) — shared React UI library- Exports component entry points via
"./*": "./src/components/ui/*.tsx". - Exports shared stylesheet via
"./styles.css": "./src/styles/globals.css". - Uses package-local
#...aliases (for example#utils) viapackage.json#imports+tsconfigpaths. - Why: keeps internal imports ergonomic without leaking app-specific aliases (like
~/...) into consumers.
- Exports component entry points via
-
packages/tailwind-config(@repo/tailwind-config) — shared Tailwind v4 primitives- Exports
tailwind-styles.cssand a reusable PostCSS config (./postcss). - Why: one source of theme/utilities used by both app and package styles.
- Exports
-
packages/db(@repo/db) — Prisma + Postgres integration- Owns Prisma schema, migrations, generated client, and Dockerized local Postgres.
- Exports a configured
prismaclient fromsrc/client.ts. - Why: DB concerns are isolated from apps and reusable across services.
-
packages/schema(@repo/schema) — shared Zod schemas + types- Exports request/response validation models used by API and clients.
- Why: shared contracts reduce mismatch bugs between frontend and backend.
-
packages/biome-config/packages/typescript-config- Centralized linting and TS config presets for consistency.
Tailwind works across app + shared UI because all three pieces are present:
apps/web/app/globals.cssimports both:@repo/ui/styles.css@repo/tailwind-config
apps/web/postcss.config.jsuses@repo/tailwind-config/postcss.- Shared UI package exposes its stylesheet through
@repo/ui/styles.css.
If one of these is missing, classes from shared UI components can appear to “not work”.
From repo root:
pnpm dev— runs alldevtasks in Turbopnpm build— runs all build taskspnpm lint— runs Biome across workspacepnpm check-types— runs type checks across workspace
Per-app/package examples:
pnpm --filter web devpnpm --filter api devpnpm --filter @repo/db startpnpm --filter @repo/db migrate:dev
-
Install dependencies
pnpm install
-
Set up database env
cp packages/db/.env.example packages/db/.env
-
Start Postgres and apply migrations
pnpm --filter @repo/db start pnpm --filter @repo/db migrate:dev
-
Run apps
pnpm dev
Default ports:
- Web:
http://localhost:3000 - API:
http://localhost:3001 - Postgres (docker):
5433
- Use
#...aliases only insidepackages/uifor internal module ergonomics. - Use package imports (
@repo/ui,@repo/schema,@repo/db) across workspace boundaries. - Keep validation rules in
@repo/schema; avoid duplicating Zod schemas in apps. - Keep DB logic in
@repo/db; consume the exported client in apps.