https://github.com/jdizm/turbo-nuxt-starter
A turborepo starter example with vue, nuxt, nitro, storybook, tailwind
https://github.com/jdizm/turbo-nuxt-starter
api frontend fullstack monorepo nitro nuxt storybook tailwindcss template turbo turborepo vue
Last synced: 6 months ago
JSON representation
A turborepo starter example with vue, nuxt, nitro, storybook, tailwind
- Host: GitHub
- URL: https://github.com/jdizm/turbo-nuxt-starter
- Owner: JDIZM
- Created: 2024-07-05T19:46:40.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2025-09-28T11:07:38.000Z (10 months ago)
- Last Synced: 2025-09-28T13:08:33.163Z (10 months ago)
- Topics: api, frontend, fullstack, monorepo, nitro, nuxt, storybook, tailwindcss, template, turbo, turborepo, vue
- Language: Vue
- Homepage:
- Size: 2.54 MB
- Stars: 5
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Turbo Nuxt Starter - Turborepo + Nuxt 4 + Vue 3 Monorepo
A production-ready **Turborepo monorepo starter** template for building modern full-stack applications with **Nuxt 4**, **Vue 3**, Express/Nitro APIs, and PostgreSQL. Perfect for developers looking for a comprehensive **TypeScript monorepo** with component libraries, documentation, and production-grade infrastructure.
## π Features
### Full-Stack Monorepo Architecture
- **Turborepo** - Intelligent build system with caching and parallel execution
- **Multiple Apps** - Nuxt 4 frontend, Express API, Nitro server, Storybook, and Docus documentation
- **Workspace Packages** - Shared UI components, type definitions, utilities, and database schemas
- **pnpm 10** - Fast, disk-efficient package manager with built-in security features
### Frontend Excellence
- **Nuxt 4 + Vue 3** - Modern SSR framework with Composition API
- **Tailwind CSS + DaisyUI** - Utility-first styling with pre-built components
- **Pinia** - Type-safe state management
- **Storybook** - Component-driven development with isolated testing
- **TypeScript** - Full type safety across the entire stack
### Backend Flexibility
- **Express API** - Production-ready REST API with middleware, auth, and OpenAPI docs
- **Nitro Server** - Modern server framework with edge deployment support
- **PostgreSQL + Drizzle ORM** - Type-safe database with migrations and seed data
- **Zod Validation** - Runtime schema validation with auto-generated TypeScript types
### Production-Ready Infrastructure
- **Docker Support** - Multi-stage builds with BuildKit caching and turbo prune
- **GCP Cloud Run** - Terraform infrastructure with Workload Identity Federation
- **CI/CD Pipelines** - GitHub Actions with automated deployments
- **Corepack** - Automatic package manager version management
- **Security** - Lifecycle script protection, minimum release age, rate limiting
- **Structured Logging** - Pino logger for request tracking and debugging
- **API Documentation** - Auto-generated OpenAPI/Swagger documentation
- **Database Tools** - Drizzle Kit migrations with type-safe schema management
- **Renovate** - Automated dependency updates with smart grouping
### Developer Experience
- **Docus Documentation** - Beautiful docs site powered by Nuxt Content
- **Hot Module Replacement** - Fast development with instant updates
- **Shared TypeScript Configs** - Consistent tsconfig across all packages
- **ESLint + Prettier** - Code quality and formatting enforcement
- **CI/CD Ready** - GitHub Actions workflows with prepare commands
## Why This Starter?
### π― Comprehensive Yet Flexible
Unlike minimal starters, this template provides **production-grade infrastructure** out of the box while remaining flexible enough to remove what you don't need. Choose between Express or Nitro for your API, use Storybook for component development, and deploy with Docker.
### π Security-First Approach
Built with **pnpm 10's latest security features** including lifecycle script protection and minimum release age settings. These features became critical after major npm supply chain attacks in 2025.
### π¦ True Monorepo Architecture
Leverages **Turborepo** for intelligent caching and parallel task execution. Shared packages (ui, helpers, api-types, db-schema, logger) demonstrate real-world monorepo patterns used in production applications.
### π Modern Tech Stack
- **Nuxt 4.1+** - Latest stable with Vue 3.5+ and Vite 6
- **TypeScript 5.7+** - Strict mode with comprehensive type safety
- **pnpm 10** - Fastest package manager with built-in security
- **Node 22+ LTS** - Future-proof with long-term support
### π Documentation-Driven
Includes **Docus** (powered by Nuxt 4 + Nuxt Content) for beautiful, searchable documentation. Markdown-based content with Vue component support makes it easy to maintain comprehensive docs alongside your code.
### π¨ Component Library Ready
**Storybook integration** with pre-built UI components (Button, Input, Card, Modal, Alert, Badge) demonstrates component-driven development patterns. Perfect for design systems and reusable components.
### ποΈ Database-Ready
PostgreSQL + Drizzle ORM setup with migrations, seeds, and type-safe queries. Supabase Studio provides database management UI.
## π Quick Start
### Prerequisites
- \*\*Node.js 22+ (LTS) - [Download](https://nodejs.org/)
- **Corepack** - Package manager version manager (included with Node.js 16+)
- **Docker** (for database) - [Get Docker](https://docs.docker.com/get-docker/)
Enable Corepack if not already enabled:
```bash
corepack enable
```
### Installation
```bash
# Clone the repository
git clone https://github.com/your-org/turbo-nuxt-starter.git
cd turbo-nuxt-starter
# Install dependencies
pnpm install
# Rebuild native modules (required for Docus/better-sqlite3)
pnpm rebuild better-sqlite3
# Copy environment variables
cp .env.example .env
# Start PostgreSQL with Docker
docker-compose up -d postgres
# Run database migrations
cd packages/db-schema
pnpm migrate:push
cd ../..
# Start all apps
pnpm dev
```
## π Supabase Local Development
This starter includes **Supabase authentication** with local Docker development. No cloud account needed for development!
The `supabase/` directory at the root contains the Supabase CLI configuration shared by all apps.
### Start Supabase
```bash
# Install Supabase CLI (if not already installed)
pnpm add -g supabase
# Start local Supabase stack from root (PostgreSQL, Auth, Storage, etc.)
supabase start
```
### Configure Environment
This monorepo uses a **single root `.env` file** for all shared configuration.
1. **Copy the example file:**
```bash
cp .env.example .env
```
2. **Fill in Supabase credentials** from `supabase start` output:
```bash
# Get credentials
supabase status -o env
# Copy these to root .env:
# - DATABASE_URL (replace )
# - SUPABASE_PUBLISHABLE_KEY
# - SUPABASE_SECRET_KEY
# - SUPABASE_JWT_SECRET
```
3. **(Optional) Add app-specific configuration:**
- **API**: `apps/api/.env` - OpenAPI config, Sentry DSN
- **Nuxt**: `apps/nuxt/.env` - Generate secret with `openssl rand -base64 32`
- **Nitro**: `apps/nitro/.env` - Port overrides
#### Environment Variable Inheritance
```
βββββββββββββββββββββββββββββββββββββββ
β Root .env (Single Source of Truth) β
β β’ DATABASE_URL β
β β’ SUPABASE_* (all keys) β
β β’ CORS_ORIGIN β
β β’ All application ports β
β β’ LOG_LEVEL β
βββββββββββββββ¬ββββββββββββββββββββββββ
β Inherited by all apps β
βββββββββββ΄ββββββββββ¬βββββββββββββββ¬βββββββββββββββ
β β β β
βββββΌβββββββ ββββββββΌββββ βββββββΌβββββ ββββββΌββββββ
β apps/api β βapps/nuxt β βapps/nitroβ βapps/docusβ
β .env β β .env β β .env β β β
β (OpenAPI)β β (Secrets)β β (Port) β β (none) β
ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ
```
**Benefits:**
- β
**DRY** - No duplicated env var definitions
- β
**Single setup** - Copy one file, configure once
- β
**Clear separation** - Obvious which vars are app-specific
- β
**Docker-friendly** - `docker-compose` reads root `.env` automatically
**About Supabase Keys:**
- **API Keys** (`sb_publishable_*` or `anon`): For SDK initialization - functionally equivalent
- **JWT System**: Newer asymmetric keys enable local token verification (faster, more secure)
- Both servers use `supabase.auth.getClaims()` which automatically uses Web Crypto API with asymmetric keys
- Learn more: [Supabase API Keys](https://supabase.com/docs/guides/api/api-keys) | [JWT Signing Keys](https://supabase.com/blog/jwt-signing-keys)
### Run Database Migrations
```bash
cd packages/db-schema
pnpm migrate:push
```
### Seed Test Accounts (Optional)
```bash
cd apps/api
pnpm seed
```
This creates 3 test accounts in Supabase Auth + database:
- alice@example.com / password123
- bob@example.com / password123
- charlie@example.com / password123
### Access Supabase Studio
Supabase Studio (web UI) runs at **http://localhost:54323**
Manage users, view database, test Auth, and more!
### Authentication Flow
1. **Sign up a user** (creates Supabase Auth user + account record):
```bash
curl -X POST http://localhost:3002/api/auth/signup \
-H "Content-Type: application/json" \
-d '{"email":"alice@example.com","password":"password123","fullName":"Alice Johnson"}'
```
2. **Sign in** (returns JWT access token):
```bash
curl -X POST http://localhost:3002/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"alice@example.com","password":"password123"}'
```
3. **Access protected endpoints** (use JWT token):
```bash
curl http://localhost:3002/api/me \
-H "Authorization: Bearer "
```
### How Auth Works
- **Supabase Auth** handles passwords, JWT tokens, sessions
- **Both APIs** verify JWT tokens using `supabase.auth.getClaims()`
- With asymmetric keys: Local verification using Web Crypto API (fast, offline)
- With symmetric keys: Falls back to Auth server verification
- **Account UUID** matches Supabase Auth user ID (synced on signup)
- **Protected routes** require `Authorization: Bearer ` header
### Useful Commands
```bash
# Check Supabase services status
supabase status
# Stop all services
supabase stop
# Reset database (WARNING: deletes all data)
supabase db reset
# Generate migration from schema changes
supabase db diff -f migration_name
```
## What's inside?
This Turborepo includes the following packages/apps:
### Apps and Packages
- **`vite`** - [Vite](https://vitejs.dev/) + Vue 3 application (port 3000)
- **`nuxt`** - [Nuxt 4](https://nuxt.com/) frontend application (port 3001)
- **`api`** - [Express API](https://expressjs.com/) server with TypeScript (port 3002)
- **`docus`** - [Docus](https://docus.dev/) documentation site (port 3003)
- **`nitro`** - [Nitro](https://nitro.unjs.io/) server example (port 3004)
- **`storybook`** - [Storybook](https://storybook.js.org/) for component development (port 6006)
- **`ui`** - Shared Vue component library with Tailwind CSS
- **`eslint-config-custom`** - ESLint configurations for different environments
- **`tsconfig`** - Shared TypeScript configurations
- **`tailwind-config`** - Shared Tailwind CSS configuration
Each package/app is 100% [TypeScript](https://www.typescriptlang.org/).
### Utilities
This Turborepo has some additional tools already setup for you:
- [TypeScript](https://www.typescriptlang.org/) for static type checking
- [ESLint](https://eslint.org/) for code linting
- [Prettier](https://prettier.io) for code formatting
## Development
### Start All Services
Run all applications simultaneously:
```bash
pnpm dev
```
This starts all applications on their configured ports:
| Application | Port | URL | Environment Variable |
| ------------- | ---- | --------------------- | -------------------- |
| Vite + Vue 3 | 3000 | http://localhost:3000 | - |
| Nuxt Frontend | 3001 | http://localhost:3001 | NUXT_PORT |
| Express API | 3002 | http://localhost:3002 | API_PORT |
| Docus Docs | 3003 | http://localhost:3003 | DOCS_PORT |
| Nitro Server | 3004 | http://localhost:3004 | NITRO_PORT |
| Storybook | 6006 | http://localhost:6006 | - |
**Infrastructure Services:**
| Service | Port | URL | Environment Variable |
| --------------- | ----- | ---------------------------- | -------------------- |
| Supabase Studio | 54323 | http://localhost:54323 | - |
| Supabase API | 54321 | http://localhost:54321 | SUPABASE_URL |
| PostgreSQL | 54322 | postgresql://localhost:54322 | POSTGRES_PORT |
### Individual Services
Start specific services:
```bash
# Start only the API server
pnpm dev:api
# Start only the Nuxt frontend
pnpm dev:web
# Start Storybook
pnpm --filter storybook storybook
```
### Build
Build all applications and packages:
```bash
pnpm build
```
### Dual Server Architecture
This monorepo provides **two production-ready API server options**:
| Feature | Express (Port 3002) | Nitro (Port 3004) |
| -------------- | -------------------------------- | --------------------------------- |
| **Routing** | Manual registration | File-based (automatic) |
| **OpenAPI** | `@asteasolutions/zod-to-openapi` | Built-in `defineRouteMeta` |
| **Deployment** | Traditional servers | Edge-optimized, serverless |
| **Ecosystem** | Mature, extensive middleware | Modern, growing |
| **Best For** | Complex middleware chains | Fast prototyping, edge deployment |
**Shared Foundation:**
- Both use identical workspace packages (api-types, db-schema, helpers, logger)
- Same authentication flow (Supabase JWT verification)
- Identical response formats and error handling
- Complete database-backed CRUD operations with PostgreSQL + Drizzle ORM
### API Endpoints
Both servers provide the same core functionality with slightly different route paths:
#### Authentication Endpoints (Public)
| Method | Express Route | Nitro Route | Description |
| ------ | ------------------ | ------------------ | ------------------------------ |
| POST | `/api/auth/signup` | `/api/auth/signup` | Create new user account |
| POST | `/api/auth/login` | `/api/auth/login` | Authenticate and get JWT token |
| POST | `/api/auth/logout` | `/api/auth/logout` | Logout (protected) |
#### User Endpoints (Protected - Requires JWT)
| Method | Express Route | Nitro Route | Description |
| ------ | ---------------- | ----------- | ------------------------------ |
| GET | `/api/me` | `/api/me` | Get current user from database |
| GET | `/api/users` | `/user` | List all users |
| GET | `/api/users/:id` | `/user/:id` | Get user by ID |
| PATCH | `/api/users/:id` | `/user/:id` | Update user (self-update only) |
| DELETE | `/api/users/:id` | `/user/:id` | Delete user (self-delete only) |
#### Health & Info Endpoints
| Method | Express Route | Nitro Route | Description |
| ------ | ------------- | ----------- | ------------------- |
| GET | `/health` | `/health` | Server health check |
| GET | `/api/` | - | API information |
### OpenAPI Documentation
Both servers provide interactive API documentation:
- **Express Swagger UI**: http://localhost:3002/docs
- **Nitro Swagger UI**: http://localhost:3004/\_swagger
- **Nitro Scalar UI**: http://localhost:3004/\_scalar
Both support the **"Authorize" button** for testing protected endpoints with JWT tokens.
### Example API Requests
#### Signup
```bash
curl -X POST http://localhost:3002/api/auth/signup \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securePassword123",
"fullName": "John Doe"
}'
```
#### Login
```bash
curl -X POST http://localhost:3002/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securePassword123"
}'
```
Response includes JWT token:
```json
{
"code": 200,
"data": {
"user": { "id": "...", "email": "..." },
"session": { "access_token": "eyJ...", "expires_in": 3600 },
"message": "Sign in successful"
}
}
```
#### Get Current User (Protected)
```bash
curl http://localhost:3002/api/me \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
```
#### List Users (Protected)
```bash
curl http://localhost:3002/api/users \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
```
#### Update User (Protected - Self-Update Only)
```bash
curl -X PATCH http://localhost:3002/api/users/USER_UUID \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"fullName": "Jane Doe Updated",
"email": "updated@example.com"
}'
```
**Authorization Pattern**: Users can only update or delete their own accounts. Attempting to modify another user's account returns `403 Forbidden`.
### Database Integration
Both servers use **PostgreSQL with Drizzle ORM** for type-safe database operations:
- **Connection**: Singleton pattern with `getDb()` from db-schema package
- **Schema**: Shared `accounts` table with uuid, email, fullName, createdAt
- **Migrations**: `pnpm db:migrate` applies schema changes
- **Seeding**: `pnpm db:seed` populates test data
- **Studio**: `pnpm db:studio` opens Drizzle Studio for visual database management
Database connection details:
```bash
# PostgreSQL (via Supabase)
Host: localhost
Port: 54322
Database: postgres
User: postgres
Password: postgres
```
## π³ Docker Deployment
This monorepo includes complete Docker configurations for all applications with optimized multi-stage builds.
### Quick Start
```bash
# Build and start all services
docker compose build
docker compose up -d
# Or combine into one command
docker compose up -d --build
# View logs
docker compose logs -f
# Stop all services
docker compose down
```
### Available Docker Services
All applications have individual Dockerfiles with multi-stage builds:
| Service | Port | Dockerfile | Description |
| ------------- | ----- | --------------------------- | ------------------- |
| **api** | 3002 | `apps/api/Dockerfile` | Express API server |
| **nitro** | 3004 | `apps/nitro/Dockerfile` | Nitro server |
| **nuxt** | 3001 | `apps/nuxt/Dockerfile` | Nuxt SSR frontend |
| **vite** | 3000 | `apps/vite/Dockerfile` | Vite static app |
| **docus** | 3003 | `apps/docus/Dockerfile` | Documentation site |
| **storybook** | 6006 | `apps/storybook/Dockerfile` | Component library |
| **postgres** | 54322 | `postgres:16-alpine` | PostgreSQL database |
### Docker Compose Files
**docker-compose.yml** - Production environment (default):
- Optimized production builds
- Health checks for all services
- Automatic restarts
- Minimal image sizes
- Supabase integration (no PostgreSQL needed)
**docker-compose.db.yml** - Optional local PostgreSQL:
- Use this for local development without Supabase
- Includes PostgreSQL 16 on port 54322
- Persistent volume for data storage
**Note**: For local development, use `pnpm dev` directly instead of Docker. Docker is primarily for production deployment testing.
### Accessing Services
**Standard localhost access:**
- Vite: http://localhost:3000
- Nuxt: http://localhost:3001
- API: http://localhost:3002
- Docus: http://localhost:3003
- Nitro: http://localhost:3004
- Storybook: http://localhost:6006
**OrbStack users** (automatic HTTPS domains):
If you're using OrbStack instead of Docker Desktop, containers are automatically available at:
- Vite: https://vite.turbo-nuxt-starter.orb.local
- Nuxt: https://nuxt.turbo-nuxt-starter.orb.local
- API: https://api.turbo-nuxt-starter.orb.local
- Docus: https://docus.turbo-nuxt-starter.orb.local
- Nitro: https://nitro.turbo-nuxt-starter.orb.local
- Storybook: https://storybook.turbo-nuxt-starter.orb.local
OrbStack provides automatic local DNS and SSL certificates for all running containers.
### Building Individual Images
```bash
# Build specific app
docker build -f apps/api/Dockerfile -t turbo-api .
# Build with BuildKit caching
DOCKER_BUILDKIT=1 docker build -f apps/api/Dockerfile -t turbo-api .
```
### Common Docker Commands
```bash
# Build all services
docker compose build
# Start services in background
docker compose up -d
# Build and start (no cache)
docker compose build --no-cache && docker compose up -d
# View logs
docker compose logs -f api
# Stop all services
docker compose down
# Remove volumes
docker compose down -v
# Start with optional PostgreSQL database
docker compose -f docker-compose.yml -f docker-compose.db.yml up -d
```
### Environment Variables
Docker services use environment variables from your `.env` file:
```bash
# Copy example environment file
cp .env.example .env
# Fill in required Supabase credentials
# Get from: supabase status -o env
SUPABASE_URL=http://localhost:54321
SUPABASE_ANON_KEY=your-anon-key
SUPABASE_AUTH_JWT_SECRET=your-jwt-secret
```
**Note**: `DATABASE_URL` is the connection string used by application code. Individual `POSTGRES_*` vars configure the PostgreSQL container in `docker-compose.db.yml`.
### Docker Networking
**Important**: Docker containers cannot access `localhost` - it refers to the container itself, not your host machine.
- **Local dev (pnpm dev)**: Use `localhost` in URLs
- **Docker accessing host services**: Replace `localhost` with `host.docker.internal`
- **Production**: Use your hosted Supabase project URL (e.g., `https://your-project.supabase.co`)
Example for Docker Compose accessing local Supabase:
```bash
SUPABASE_URL=http://host.docker.internal:54321
DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:54322/postgres
```
### Docker Image Optimization
All Dockerfiles use:
- **Multi-stage builds** - Separate build and runtime stages
- **BuildKit cache mounts** - Faster dependency installation
- **pnpm** - Efficient monorepo package management
- **Node 22 Alpine** - Minimal base images (~50MB)
- **Non-root users** - Enhanced security
### Health Checks
Production services include health checks:
```yaml
# API health check (defined in Dockerfile)
healthcheck:
test:
[
"CMD",
"node",
"-e",
"require('http').get('http://localhost:3002/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
]
interval: 30s
timeout: 3s
retries: 3
start_period: 40s
```
Check service health:
```bash
docker compose ps
```
### Local Development vs Production
**Local Development (pnpm dev)**
- Uses `tsx` for on-the-fly TypeScript execution
- Reads workspace packages as TypeScript source files
- No build step required
- Hot reload enabled
**Production/Docker (pnpm start)**
- Requires transpiled output (`dist/` directory)
- Needs `node_modules` with built workspace packages
- Express API depends on external workspace packages
- Nuxt uses self-contained `.output` directory (includes bundled dependencies)
**Why pnpm start fails locally:**
The Express API (`apps/api`) uses workspace packages (`logger`, `db-schema`, etc.) as TypeScript source. When tsup transpiles the API, it doesn't bundle these workspace packages. Docker containers include `node_modules` from the installer stage, but running `pnpm start` locally without a full workspace build will fail with TypeScript import errors.
### Troubleshooting
**Issue: Build fails with "permission denied"**
```bash
# Use BuildKit
export DOCKER_BUILDKIT=1
docker-compose build
```
**Issue: Port already in use**
```bash
# Change ports in .env file
API_PORT=3012
NUXT_PORT=3011
```
**Issue: Services can't connect to database**
```bash
# Use Docker service name for DATABASE_URL
DATABASE_URL=postgresql://postgres:postgres@postgres:5432/postgres
```
## Project Structure
```
turbo-nuxt-starter/
βββ apps/
β βββ api/ # Express.js API server
β β βββ src/
β β β βββ routes/ # API routes
β β β βββ server.ts # Main server file
β β βββ package.json
β β βββ tsconfig.json
β βββ nuxt/ # Nuxt 3 frontend
β βββ nitro/ # Nitro server example
β βββ storybook/ # Component development
β βββ vite/ # Vite + Vue 3 app
βββ packages/
β βββ ui/ # Shared Vue components
β βββ eslint-config-custom/ # ESLint configurations
β βββ tsconfig/ # TypeScript configurations
β βββ tailwind-config/ # Tailwind CSS config
βββ package.json # Root workspace config
βββ turbo.json # Turborepo configuration
```
## Environment Configuration
### API Environment Variables
Copy `.env.example` to `.env` in the API directory:
```bash
cp apps/api/.env.example apps/api/.env
```
Configure as needed:
- `PORT` - API server port (default: 3002)
- `NODE_ENV` - Environment (development/production)
- `CORS_ORIGIN` - CORS allowed origin
## Adding New Features
### New API Routes
1. Create route file in `apps/api/src/routes/`
2. Export router and import in `apps/api/src/routes/index.ts`
### New UI Components
1. Add component to `packages/ui/`
2. Export from `packages/ui/index.ts`
3. Use in any app: `import { MyComponent } from 'ui'`
### Shared Types
Add TypeScript types to `packages/ui/types/` for cross-package usage.
### Remote Caching
Turborepo can use a technique known as [Remote Caching](https://turbo.build/repo/docs/core-concepts/remote-caching) to share cache artifacts across machines, enabling you to share build caches with your team and CI/CD pipelines.
By default, Turborepo will cache locally. To enable Remote Caching you will need an account with Vercel. If you don't have an account you can [create one](https://vercel.com/signup), then enter the following commands:
```
cd my-turborepo
npx turbo login
```
This will authenticate the Turborepo CLI with your [Vercel account](https://vercel.com/docs/concepts/personal-accounts/overview).
Next, you can link your Turborepo to your Remote Cache by running the following command from the root of your Turborepo:
```
npx turbo link
```
## CI/CD Setup
### TypeScript Configuration Generation
Nuxt and Nitro apps generate their TypeScript configurations at prepare time:
- `apps/nuxt/.nuxt/tsconfig.json` - Generated by `nuxt prepare`
- `apps/nitro/.nitro/tsconfig.json` - Generated by `nitro prepare`
- `apps/docus/.nuxt/tsconfig.json` - Generated by `nuxt prepare --extends docus`
**Local Development:**
- These are generated automatically via `postinstall` scripts when you run `pnpm install`
- No manual action required
**CI/CD Pipelines:**
- If you skip postinstall scripts (common practice with `--ignore-scripts`), you must run `turbo prepare` before typechecking
- This ensures all `.nuxt` and `.nitro` directories are generated with proper TypeScript configurations
### Example GitHub Actions Workflow
```yaml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 10.17.1
- uses: actions/setup-node@v4
with:
node-version: 22
cache: "pnpm"
# Install dependencies (skip postinstall for speed)
- run: pnpm install --frozen-lockfile --ignore-scripts
# Rebuild native modules
- run: pnpm rebuild better-sqlite3
# Generate TypeScript configs for Nuxt/Nitro
- run: turbo prepare
# Run quality checks
- run: turbo lint:check
- run: turbo typecheck
- run: turbo test:unit
- run: turbo build
```
### Manual Prepare Command
If you need to manually regenerate TypeScript configurations:
```bash
# Regenerate all configs
turbo prepare
# Or for a specific app
pnpm --filter nuxt prepare
pnpm --filter nitro prepare
pnpm --filter docus prepare
```
## Useful Links
Learn more about the power of Turborepo:
- [Tasks](https://turbo.build/repo/docs/core-concepts/monorepos/running-tasks)
- [Caching](https://turbo.build/repo/docs/core-concepts/caching)
- [Remote Caching](https://turbo.build/repo/docs/core-concepts/remote-caching)
- [Filtering](https://turbo.build/repo/docs/core-concepts/monorepos/filtering)
- [Configuration Options](https://turbo.build/repo/docs/reference/configuration)
- [CLI Usage](https://turbo.build/repo/docs/reference/command-line-reference)
## Troubleshooting
### TypeScript Configuration Not Found
If `pnpm typecheck` fails with errors about missing TypeScript configurations or cannot find auto-imported functions (`useHead`, `defineNuxtConfig`, etc.):
**Cause:** The `.nuxt` and `.nitro` directories haven't been generated yet.
**Solution:**
```bash
# Regenerate TypeScript configurations
turbo prepare
# Then run typecheck again
pnpm typecheck
```
This is especially common in CI/CD environments when using `pnpm install --ignore-scripts`. See the [CI/CD Setup](#cicd-setup) section for more details.
### better-sqlite3 Bindings Error
If you encounter an error like `Could not locate the bindings file` when running the Docus app, it means the native module `better-sqlite3` needs to be rebuilt for your system.
**Error example:**
```
Error: Could not locate the bindings file. Tried:
β /path/to/node_modules/better-sqlite3/build/better_sqlite3.node
```
**Solution:**
```bash
# Rebuild the native module
pnpm rebuild better-sqlite3
```
This is required because `better-sqlite3` is a native Node.js addon that must be compiled for your specific:
- Node.js version (e.g., Node 22.17.0)
- Operating system (macOS, Linux, Windows)
- CPU architecture (arm64, x64)
The rebuild command will compile the module correctly for your environment.
## Deployment
This monorepo includes complete infrastructure for deploying to **GCP Cloud Run**.
### Quick Deployment
```bash
# 1. Configure Terraform
cd infra/terraform
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars with your GCP project ID
# 2. Apply infrastructure
terraform init
terraform apply
# 3. Push images
gcloud auth configure-docker europe-west1-docker.pkg.dev
docker build -f apps/api/Dockerfile -t europe-west1-docker.pkg.dev/PROJECT/turbo-repo/api:latest .
docker push europe-west1-docker.pkg.dev/PROJECT/turbo-repo/api:latest
```
### What's Included
| Component | Description |
| ------------------------------ | ----------------------------------------------------- |
| `infra/terraform/` | GCP Cloud Run, Artifact Registry, Secret Manager, IAM |
| `.github/workflows/ci.yml` | Lint, typecheck, test, build on PRs |
| `.github/workflows/deploy.yml` | Build Docker images, deploy to Cloud Run |
| `renovate.json` | Automated dependency updates |
| `docker-compose.dev.yml` | Local development with hot reload |
### CI/CD Workflows
- **ci.yml** - Runs on all PRs: lint, typecheck, test, build
- **deploy.yml** - Runs on main: build images, deploy to Cloud Run
### GitHub Secrets Required
| Secret | Description |
| -------------------------------- | ----------------------- |
| `GCP_PROJECT_ID` | Your GCP project ID |
| `GCP_REGION` | e.g., `europe-west1` |
| `GCP_WORKLOAD_IDENTITY_PROVIDER` | From `terraform output` |
| `GCP_SERVICE_ACCOUNT` | From `terraform output` |
### Documentation
Full deployment documentation is available at:
- **Docus Site**: Run `pnpm --filter docus dev` and visit http://localhost:3003/deployment
- **Infrastructure README**: `infra/README.md`
## Security Features (pnpm 10)
This starter uses **pnpm 10** with enhanced security features to protect against supply chain attacks.
### Lifecycle Script Protection
**By default, lifecycle scripts from dependencies are disabled.** This prevents malicious packages from executing arbitrary code during installation.
Only explicitly allowed packages can run lifecycle scripts, configured in `pnpm-workspace.yaml`:
```yaml
onlyBuiltDependencies:
- better-sqlite3 # Native module requiring compilation
- esbuild # Build tool needing platform binaries
```
If you need to allow additional packages to run lifecycle scripts, add them to this list.
### Minimum Release Age
**New package versions are delayed by 24 hours before installation** to give the community time to identify malicious releases.
```yaml
minimumReleaseAge: 1440 # 24 hours in minutes
```
This setting is configured in `pnpm-workspace.yaml` and helps protect against:
- Compromised maintainer accounts
- Malicious package updates
- Supply chain injection attacks
**Note:** This only affects newly published versions. Existing versions install immediately.
### Package Manager Version Management
Corepack automatically manages the pnpm version based on the `packageManager` field in `package.json`:
```json
{
"packageManager": "pnpm@10.17.1"
}
```
This ensures everyone on your team uses the same pnpm version, eliminating "works on my machine" issues.
### Learn More
- [pnpm Supply Chain Security](https://pnpm.io/supply-chain-security)
- [pnpm 10 Release Notes](https://pnpm.io/blog/releases/10.16)
- [Corepack Documentation](https://nodejs.org/api/corepack.html)