Modern PERN stack monorepo for rapid prototyping and production applications with Turborepo, Biome, strict type safety, and composable deployment across web, API, agents, and shared packages.
# Prerequisites: Docker Desktop running
# 1. Clone and install
cp -r /path/to/ts-fullstack my-app
cd my-app
yarn install
# 2. Setup environment
cp .env.example .env
# Edit .env if needed (defaults work for local dev)
# 3. Start local database
yarn docker:up
# 4. Setup database
yarn db:push # Push schema to database
yarn db:seed # Seed with test data
# 5. Start development (all services with Turbo)
yarn dev # Start API + Web + Agent (parallel)
# Or run separately:
yarn dev:api # API only (http://localhost:3000)
yarn dev:web # Web only (http://localhost:5173)
yarn dev:agent # Agent only (http://localhost:3001)
# 6. Verify quality
yarn build # Turbo: build all packages
yarn lint:check # Biome: 0 warnings enforced
yarn test # Vitest: all tests must passFrontend:
- React 18 + TypeScript
- Vite (fast dev + HMR)
- TanStack Query (data fetching)
- React Router (routing)
- Tailwind CSS + Shared UI Components (
@adaptiveworx/ui)
Backend:
- Fastify (high-performance HTTP)
- Drizzle ORM (type-safe SQL)
- PostgreSQL 17 (via Docker)
- Redis (caching/sessions)
- Zod (runtime validation)
Agent Services:
- LLM/worker orchestration (
@adaptiveworx/agent) - MCP-compatible tool structure
- Multi-step workflows
Developer Experience:
- Turborepo - Incremental builds, remote caching, smart DAG execution
- Biome - 100x faster linting + formatting (replaces ESLint + Prettier)
- Yarn 4 node-modules - Better compatibility with IaC/Docker
- TypeScript strict mode (@tsconfig/strictest)
- ESM-first (NodeNext)
- Monorepo workspaces (apps, packages, envs)
ts-fullstack/
βββ apps/
β βββ api/ # @adaptiveworx/api - Fastify API server
β β βββ src/routes/ # API route handlers
β β βββ package.json
β βββ web/ # @adaptiveworx/web - React frontend (Vite)
β β βββ src/components/
β β βββ package.json
β βββ [future: admin, mobile-web, etc.]
βββ packages/
β βββ db/ # @adaptiveworx/db - Drizzle ORM, schemas
β β βββ src/schema/ # Table definitions
β β βββ client.ts # Database client
β β βββ seed.ts
β βββ shared/ # @adaptiveworx/shared - Common types, utils
β β βββ src/config/ # Secrets manager (Infisical)
β β βββ src/types/
β β βββ src/utils/
β βββ ui/ # @adaptiveworx/ui - Shared React components
β β βββ src/components/ # Button, Input, Card, etc.
β β βββ src/styles/ # Tailwind globals
β βββ agent/ # @adaptiveworx/agent - LLM/worker services
β βββ src/tools/ # Agent tools (MCP or custom)
β βββ src/workflows/ # Multi-step orchestrations
βββ envs/ # Environment-specific configs
β βββ dev/ # Development (local + cloud dev)
β βββ stg/ # Staging (pre-production)
β βββ prd/ # Production
βββ .github/workflows/ # CI/CD pipelines
βββ turbo.json # Turborepo pipeline config
βββ biome.json # Biome linter + formatter config
βββ package.json # Root monorepo scripts
- Rapid Prototyping: Full-stack app in < 5 minutes
- AI-First Apps: Agent package ready for LLM orchestration
- Multi-Environment Deploys: Dev/Stg/Prd version pinning
- Paired Programming: Vibe-coding with candidates
- Hackathons: Production patterns, zero setup time
- Internal Tools: CRUD apps with type safety
- MVPs: Production-ready from day one
yarn dev # Turbo: run all services in parallel
yarn dev:api # API only (port 3000)
yarn dev:web # Web only (port 5173)
yarn dev:agent # Agent only (port 3001)yarn db:push # Push schema changes to database
yarn db:reset # Drop all tables (destructive!)
yarn db:seed # Seed with test datayarn docker:up # Start PostgreSQL + Redis
yarn docker:down # Stop containers
docker ps # Check running containersyarn build # Turbo: build all packages (must pass!)
yarn type-check # TypeScript compilation (all workspaces)
yarn lint:check # Biome: 0 warnings enforced
yarn lint:fix # Biome: auto-fix issues
yarn test # Turbo: run all tests
yarn test:coverage # Coverage reportsZero-Tolerance Policies:
- β 0 TypeScript errors
- β 0 Biome warnings
- β All tests passing
- β Strict mode enabled (@tsconfig/strictest)
Enforced via:
exactOptionalPropertyTypes: true- Catch undefined edge casesnoUncheckedIndexedAccess: true- Array/object safetynoPropertyAccessFromIndexSignature: true- Explicit property access- Turborepo caching validates all checks before build
Uses root .env file and local Docker services.
Each environment pins specific package versions:
// envs/prd/package.json
{
"dependencies": {
"@adaptiveworx/api": "0.2.0",
"@adaptiveworx/web": "0.2.0",
"@adaptiveworx/agent": "0.1.5"
}
}Version Promotion Flow:
- Test in
envs/devwith latest versions - Promote to
envs/stgfor validation - Promote to
envs/prdfor production release
See envs/README.md for details.
// packages/db/src/schema/users.ts
import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
export const users = pgTable("users", {
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
email: text("email").notNull().unique(),
name: text("name"),
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
});
export const insertUserSchema = createInsertSchema(users);
export type User = typeof users.$inferSelect;// apps/api/src/routes/users.ts
import { db } from "@adaptiveworx/db";
import { users, insertUserSchema } from "@adaptiveworx/db";
server.get("/api/users", async () => {
const allUsers = await db.select().from(users);
return { users: allUsers };
});
server.post("/api/users", async (request) => {
const data = insertUserSchema.parse(request.body);
const [user] = await db.insert(users).values(data).returning();
return { user };
});Shared component library in @adaptiveworx/ui:
// apps/web/src/pages/MyPage.tsx
import { Button, Card, CardHeader, CardTitle, CardContent } from '@adaptiveworx/ui';
export function MyPage() {
return (
<Card>
<CardHeader>
<CardTitle>Welcome</CardTitle>
</CardHeader>
<CardContent>
<Button variant="default">Get Started</Button>
</CardContent>
</Card>
);
}// packages/agent/src/tools/example-tool.ts
import { z } from 'zod';
export const exampleTool = {
name: 'fetch_user_data',
description: 'Fetches user data from the database',
parameters: z.object({
userId: z.string().uuid(),
}),
execute: async ({ userId }) => {
const user = await db.select().from(users).where(eq(users.id, userId));
return user[0];
},
};.github/workflows/ci.yml - PR quality checks:
- Type checking (Turbo)
- Linting (Biome)
- Testing (Vitest)
- Building (Turbo with remote cache)
.github/workflows/deploy.yml - Multi-environment deploys:
- Triggered on version tags (
v*.*.*) - Matrix strategy for dev/stg/prd
- Focused workspace installs
- Pulumi infrastructure deployment
- name: Restore Turbo cache
uses: actions/cache@v4
with:
path: .turbo
key: turbo-${{ runner.os }}-${{ github.sha }}Copy .env.example to .env:
# Database (Docker local)
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/fullstack_dev
# API Server
PORT=3000
HOST=0.0.0.0
CORS_ORIGIN=http://localhost:5173
NODE_ENV=development
# Agent Server
AGENT_PORT=3001
# Infisical (optional - for production secrets)
INFISICAL_PROJECT_SLUG=your-project
INFISICAL_APPS_PROJECT_ID=your-project-idThis template follows the 5-Step Agentic Workflow:
- Collaborate on Objectives - Discuss what to build
- Agree on Architecture - Plan stacks/components
- Agent Handles Dev/Test - Claude writes code, runs builds/tests, delivers 100% clean
- User Handles Environment - User manages Docker/deployments
- Review Together - Both review results
Agent responsibilities:
- β Write TypeScript code across all packages
- β
Run
yarn build- fix ALL errors - β
Run
yarn lint:check- fix ALL warnings - β
Run
yarn test- fix ALL failures - β Deliver 100% clean code
User responsibilities:
- β Manage Docker containers
- β Run database migrations
- β Review/approve changes
- β Deploy to environments
turbo.json- Turborepo pipeline definitionsbiome.json- Linting and formatting rules.env.example- Environment variable templatedocker-compose.yml- Local PostgreSQL 17 + Redistsconfig.json- Strict TypeScript configurationpackages/*/package.json- Individual package configsenvs/*/package.json- Environment version pinning
Database connection failed:
docker ps | grep postgres
yarn docker:down && yarn docker:upPort already in use:
lsof -ti:3000 | xargs kill -9
# Or change PORT in .envTurborepo cache issues:
rm -rf .turbo
yarn build --forceType errors with Drizzle:
- Pattern:
db.insert(table).values(data as typeof table.$inferInsert)
Import errors (.js extensions):
- ESM + NodeNext requires
.jsextensions in imports - Even for
.tsfiles:import { foo } from "./bar.js"
MIT - Built for 100% agentic development by AdaptiveWorX