Skip to Content

Build System

The Sustentus monorepo uses Turborepo to orchestrate builds, manage dependencies, and cache outputs efficiently.

Overview

The build system provides:

  • Task orchestration: Run tasks across multiple packages
  • Dependency awareness: Build packages in the correct order
  • Intelligent caching: Skip unchanged work
  • Parallel execution: Run independent tasks simultaneously
  • Remote caching: Share cache across team (when configured)

Turborepo Configuration

Configuration is in turbo.json at the repository root:

{ "$schema": "https://turbo.build/schema.json", "globalDependencies": [".env"], "globalEnv": [], "remoteCache": { "enabled": true }, "tasks": { "build": { "inputs": ["$TURBO_DEFAULT$", ".env*"], "dependsOn": ["^build"], "outputs": [".next/**", "!.next/cache/**", "dist/**"] }, "dev": { "persistent": true, "cache": false, "inputs": ["$TURBO_DEFAULT$", ".env*"] }, "lint": { "inputs": ["$TURBO_DEFAULT$"], "outputs": [] }, "clean": { "cache": false, "inputs": [], "outputs": [] }, "start": { "dependsOn": ["build"], "persistent": true, "cache": false }, "env:pull": { "persistent": false, "cache": true, "inputs": ["$TURBO_DEFAULT$", ".env*"] } } }

Task Definitions

  • build: dependsOn: ["^build"] builds package dependencies first; caches Next.js builds (.next/, excluding the cache) and package builds (dist/). Source files and .env* invalidate the cache.
  • dev: persistent: true, cache: false — runs dev servers indefinitely, watching source and .env*.
  • lint: lints all source files; no outputs to cache; runs in parallel across packages.
  • clean: never cached; runs each package’s clean script (e.g. rm -rf dist).

Dependency Graph

Turborepo derives the build order from package.json dependencies. The workspace:* protocol links to the local workspace package:

{ "dependencies": { "@sustentus/ui": "workspace:*" } }

Build order:

  1. @sustentus/ui (no dependencies)
  2. @sustentus/services (no dependencies)
  3. @sustentus/marketing (depends on @sustentus/ui)
  4. @sustentus/storybook (depends on @sustentus/ui)
  5. @sustentus/docs (no dependencies)

@sustentus/ui and @sustentus/services build in parallel (no dependencies); then marketing and storybook build in parallel (both depend on ui). A change to @sustentus/ui triggers a rebuild of every downstream app.

Caching

Turbo hashes all input files, and restores cached outputs when a matching hash exists rather than re-running the task. Cache invalidates when input files, environment variables, global dependencies, or task configuration change.

  • Local cache: .turbo/cache/ (gitignored)
  • Remote cache: Vercel Remote Cache (when configured)
# Skip cache (always run) turbo run build --force # View cache hits/misses turbo run build --summarize

Package Scripts

Root Scripts

Defined in root package.json:

{ "scripts": { "build": "turbo run build", "dev": "turbo run dev", "lint": "eslint .", "clean": "turbo run clean", "format": "prettier --write \"**/*.{ts,tsx,md}\"" } }

Filter Scripts

Convenience scripts for specific packages:

{ "scripts": { "marketing:dev": "turbo run dev --filter=@sustentus/marketing", "marketing:build": "turbo run build --filter=@sustentus/marketing", "ui:dev": "turbo run dev --filter=@sustentus/ui", "ui:build": "turbo run build --filter=@sustentus/ui", "packages:build": "turbo run build --filter=@sustentus/ui --filter=@sustentus/services", "packages:dev": "turbo run dev --filter=@sustentus/ui --filter=@sustentus/services" } }

Filters also accept globs (--filter='./apps/*') and dependency selectors (--filter=@sustentus/marketing... for a package and its dependencies, --filter=...@sustentus/ui for a package and its dependents).

Build Outputs

  • Next.js apps: .next/ directory (server pages, client bundles, static assets, cache).
  • TSUP packages: dist/ directory — index.js, index.d.ts, index.js.map, and globals.css (UI package).

All build outputs are cached by Turborepo, gitignored, and cleaned by pnpm clean.

Environment Variables

.env invalidates the cache globally via globalDependencies. Tasks also watch .env* via their inputs (covering .env, .env.local, .env.development, .env.production). In CI, set env vars before building.

Learn More

Last updated on