ScaleRocket/Web

Monorepo Structure

Directory layout, Turborepo configuration, and development workflow for the pnpm monorepo.

Overview

ScaleRocket is a pnpm workspace monorepo powered by Turborepo. It contains three apps, four shared packages, and a Supabase project -- all in one repository.

Directory Structure

scalerocket/
├── apps/
│   ├── web/              # Next.js marketing site
│   ├── app/              # Vite + React dashboard (SPA)
│   └── ops/              # Vite + React admin panel
├── packages/
│   ├── ui/               # Shared component library
│   ├── config/           # Site config, pricing, constants
│   ├── types/            # TypeScript types (DB, API)
│   └── emails/           # Email templates + sending
├── supabase/
│   ├── functions/        # Edge Functions
│   ├── migrations/       # Database migrations
│   └── config.toml       # Supabase local config
├── turbo.json            # Turborepo pipeline config
├── pnpm-workspace.yaml   # Workspace definition
└── package.json          # Root scripts

apps/ -- Applications

apps/web -- Marketing Site

  • Stack: Next.js (App Router)
  • Purpose: Landing page, pricing, blog, SEO pages
  • Port: http://localhost:3000
  • Deploys to: Vercel

apps/app -- User Dashboard

  • Stack: Vite + React + React Router
  • Purpose: Authenticated user experience (dashboard, settings, billing)
  • Port: http://localhost:5173
  • Deploys to: Vercel

apps/ops -- Admin Panel

  • Stack: Vite + React
  • Purpose: Internal admin dashboard (users, subscriptions, blog)
  • Port: http://localhost:5174
  • Deploys to: Vercel (restricted access)

packages/ -- Shared Code

PackageImport AsPurpose
packages/ui@saas/uiButton, Card, Input, Toast, ThemeProvider
packages/config@saas/configsite.ts, pricing.ts, constants
packages/types@saas/typesDatabase types, API types
packages/emails@saas/emailsReact Email templates, send utility

supabase/ -- Backend

  • supabase/functions/ -- Deno-based Edge Functions
  • supabase/migrations/ -- SQL migration files
  • supabase/config.toml -- Local development configuration

Turborepo Configuration

// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "dist/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "lint": {
      "dependsOn": ["^build"]
    },
    "type-check": {
      "dependsOn": ["^build"]
    }
  }
}

Key points:

  • build depends on ^build -- packages are built before apps that use them.
  • dev is not cached and runs persistently.
  • Turborepo caches build outputs for faster rebuilds.

pnpm Workspace

# pnpm-workspace.yaml
packages:
  - "apps/*"
  - "packages/*"

.npmrc Configuration

The root .npmrc file contains:

shamefully-hoist=true

This setting is required for pnpm workspaces with shared packages. By default, pnpm creates a strict node_modules structure where each package only sees its declared dependencies. With shamefully-hoist=true, dependencies are hoisted to the root node_modules/, which is necessary because Vite resolves dependencies from the app context and needs hoisted packages to find shared dependencies from workspace packages like @saas/ui and @saas/config.

Without this setting, you may encounter "module not found" errors when apps try to use dependencies declared in shared packages.

Dev Commands

# Start everything (all apps + Supabase)
pnpm dev

# Start a specific app
pnpm --filter web dev        # Marketing site
pnpm --filter app dev        # User dashboard
pnpm --filter ops dev        # Admin panel

# Start Supabase locally
pnpm supabase start

# Start Edge Functions
pnpm supabase functions serve

Build Pipeline

# Build all apps and packages
pnpm build

# Build a specific app
pnpm --filter web build
pnpm --filter app build

# Type-check everything
pnpm type-check

# Lint everything
pnpm lint

Turborepo handles the dependency graph automatically. When you run pnpm build, it:

  1. Builds packages/types first (no dependencies)
  2. Builds packages/config and packages/ui (may depend on types)
  3. Builds packages/emails (depends on ui for components)
  4. Builds all three apps in parallel (depend on packages)

Adding a New App

  1. Create the app directory:
mkdir apps/my-app
cd apps/my-app
pnpm init
  1. Add workspace dependencies:
pnpm --filter my-app add @saas/ui @saas/config @saas/types --workspace
  1. The app is automatically picked up by the pnpm workspace and Turborepo.

Adding a New Package

  1. Create the package directory:
mkdir packages/my-package
cd packages/my-package
pnpm init
  1. Set the package name in package.json:
{
  "name": "@saas/my-package",
  "main": "./src/index.ts"
}
  1. Use it in any app:
pnpm --filter app add @saas/my-package --workspace

Done reading? Mark this page as complete.

On this page