Ollis Turborepo Test
A full-stack TypeScript monorepo demonstrating modern development practices with automatic API client generation and type-safe end-to-end data flow.
Architecture Overview
This monorepo showcases a type-safe, auto-generated API contract between backend and frontend:
Backend (Fastify) → OpenAPI Spec → Generated API Client → Frontend (SolidJS)
Key Design Decisions
-
Schema-First API Design: Backend schemas (TypeBox/JSONSchema) are the single source of truth. The OpenAPI specification is automatically generated from these schemas and actual route definitions using Fastify's
@fastify/swagger, ensuring the API contract always reflects the actual backend implementation. -
Automatic Client Generation: The
api-client-backendpackage uses@hey-api/openapi-tsto generate a fully typed API client from the OpenAPI spec, ensuring type safety across the stack. -
Turborepo Watch Mode: Development workflow uses Turborepo's watch feature to orchestrate the entire pipeline automatically - when you change an API schema, the OpenAPI spec is regenerated, the client is regenerated, and the frontend picks up changes via HMR.
-
Bare Metal Development: Apps and packages run directly on the host machine (not containerized) for faster iteration, better debugging, and native tool integration. Only external dependencies like PostgreSQL run in Docker containers via
docker-compose.
What's inside?
This Turborepo includes the following packages/apps:
Apps
frontend: a SolidJS app with CRUD UI for persons and petsbackend: a Fastify REST API with PostgreSQL and Kysely ORM
Packages
@olli/api-client-backend: Auto-generated TypeScript API client based on backend's OpenAPI spec@olli/ts-config: Shared TypeScript configurations
Utilities
- TypeScript for static type checking
- Biome for code formatting and linting
- Kysely for type-safe SQL queries
- Vitest for testing
Development Workflow
Initial Setup
- Copy environment files:
cp .env.example .env
cp apps/frontend/.env.example apps/frontend/.env
cp apps/backend/.env.example apps/backend/.env
- Start local dependencies (PostgreSQL):
docker compose up -d
- PGAdmin: http://localhost:5050
- Install dependencies:
pnpm install
Running Development Servers
The recommended way to develop is using Turborepo's watch mode:
pnpm run dev:watch
Or with global Turbo:
turbo watch dev:watch export-openapi generate
turbo watchonly works for non-persistent tasks. Sodevtasks are not affected, therefore we need to run thedev:watchtask here, so the apps actually watch changes by themselves.
What dev:watch Does
This single command orchestrates the entire development workflow:
-
Starts Development Servers (
dev:watchtask):- Backend: Runs on http://localhost:3000 with nodemon for auto-restart
- Frontend: Runs on http://localhost:5173 with Vite HMR
-
Watches for API Changes (
export-openapitask):- Monitors backend source files (
src/**/*.ts) - When API schemas change, automatically exports updated OpenAPI spec to
packages/api-client-backend/openapi.json
- Monitors backend source files (
-
Regenerates API Client (
generatetask):- Watches the OpenAPI spec file
- When spec changes, regenerates TypeScript client in
packages/api-client-backend/generated/ - Thanks to PNPM workspace linking, frontend immediately sees the updated types
-
Updates Frontend (automatic via Vite HMR):
- Vite detects changes in workspace dependencies
- Frontend auto-refreshes with new API types and methods
The Flow:
Backend code change
↓
Nodemon restarts backend server
↓
Turbo watch detects file change
↓
export-openapi script runs → generates openapi.json
↓
Turbo runs generate task → regenerates API client
↓
Vite HMR detects api-client-backend change
↓
Frontend reloads with updated types ✨
This workflow ensures zero manual steps - just change your API schema and watch it propagate through the entire stack!
Alternative Development Commands
Develop all apps and packages:
turbo dev
Develop a specific package:
turbo dev --filter=backend
turbo dev --filter=frontend
Build
Build all apps and packages:
turbo build
Build a specific package:
turbo build --filter=backend
Testing
Run all tests:
turbo test
Run tests in watch mode:
turbo test:watch
Project Structure
apps/
backend/ # Fastify API server
src/
features/ # Feature-based organization
demo/
*.routes.ts # API route handlers
*.schema.ts # Zod/TypeBox schemas
*.repository.ts
db/ # Database setup and migrations
scripts/
export-openapi.ts # OpenAPI spec generator
frontend/ # SolidJS web app
src/
person-crud.tsx # Person management UI
pet-crud.tsx # Pet management UI
api.ts # Configured API client
packages/
api-client-backend/ # Generated API client
generated/ # Auto-generated (don't edit!)
openapi.json # Source of truth from backend
Useful Links
Learn more about the power of Turborepo: