SuperAPI AI Directory

turborepo

General & other

View repository

Updated 10-15 19:57

About this skill

turborepo

Policy

Follow the combination of Turborepo and pnpm workspaces. Unify the package manager to pnpm, and commit only pnpm-lock.yaml as the lockfile.

Turborepo updates quickly, and the key names in turbo.json are also changing. If you are unsure about the shape of the configuration, do not rely on memory—look it up below.

The task definition key in turbo.json is tasks since v2. pipeline is the old name. Do not copy old articles.

Do not install Turborepo globally.pnpm exec turbo Use , or add it as a root devDependency.

Structure

my-monorepo/
  pnpm-workspace.yaml
  turbo.json
  package.json
  apps/          デプロイ可能なアプリケーション
  packages/      共有ライブラリと設定
  • The workspace structure is defined in pnpm-workspace.yaml.
  • Maintain the separation of apps and packages. Do not put deployable apps in packages. Do not put shared libraries in apps.
  • Do not create nested packages.

Packages

  • Names are @<org>/ scoped with a prefix.
  • For all internal packages, set "private": true .
  • Define exports in each package.json. Prefer exports over main.
  • Place the shared TypeScript configuration in packages/tsconfig/, and have each package inherit it.
  • Reference internal dependencies with the workspace:* protocol.

Responsibility packages

Always place the following under packages.

  • log Log aggregation
  • error Error aggregation
  • prompt AI prompt aggregation
  • env Environment variable aggregation
  • db Database aggregation

Consumers add @<org>/log etc. to workspace:* as a dependency. Do not reimplement the corresponding responsibility on the caller side.

Generating and updating package.json

Do not hand-write package.json from scratch. The same applies to the root, apps/、packages/ and either.

pnpm init                     # package.json を生成する
pnpm create <template>        # フレームワークの scaffolder を使う

Adding, updating, and removing dependencies are done with commands.

pnpm add -D -w turbo typescript                            # ルートの devDependency
pnpm add --filter @<org>/dashboard zod                     # 特定パッケージの外部依存
pnpm add --filter @<org>/dashboard --workspace @<org>/log  # 内部依存を workspace:* で解決
pnpm update --filter @<org>/dashboard
pnpm remove --filter @<org>/dashboard zod
  • When targeting something other than the root, specify the package with --filter .
  • For workspace internal dependencies, also use --workspace .
  • Do not directly edit dependencies, devDependencies, or peerDependencies.
  • Only for fields that cannot be set with commands (scoping of name, private, exports, scripts), make minimal edits to the generated package.json.

Example procedure

# ルートワークスペース
mkdir my-monorepo && cd my-monorepo
pnpm init
# pnpm-workspace.yaml に apps/* と packages/* を定義する
pnpm add -D -w turbo typescript

# 責務パッケージ
mkdir -p packages/log
(cd packages/log && pnpm init)
# name を @<org>/log にし、private と exports を設定する

# アプリ
pnpm create next-app@latest apps/dashboard
pnpm add --filter @<org>/dashboard --workspace @<org>/log

turbo.json

Define a task pipeline that takes dependencies into account.

{
  "$schema": "https://turborepo.dev/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**", "!.next/cache/**"]
    },
    "lint": {},
    "test": { "dependsOn": ["^build"] },
    "dev": { "cache": false, "persistent": true }
  }
}
  • ^build specifies that the tasks of dependency packages run first.
  • Write outputs accurately. If you omit them, they will not be restored from the cache.
  • For resident tasks like dev, cache: false と persistent: true to be.
  • if environment variables affect the build result, list them in env. If you do not list them, the cache will hit even when the environment differs.

Compilation policy

The default is the JIT (Just-in-Time) compilation pattern. Switching to the compiled pattern that outputs to dist with tsc is done only when explicitly requested.

Non-JavaScript projects

Turborepo is not JavaScript-only. Projects such as Cargo, Go, and Python can also be placed on the same task graph.

For Rust (Cargo) and Python, place a package.json in each unit you want to cache independently, and call each language's toolchain from its scripts. Turborepo does not analyze the native dependency graph; it uses the relationships on the package manager.

{
  "name": "@<org>/engine",
  "private": true,
  "scripts": {
    "build": "cargo build --release",
    "test": "cargo test",
    "lint": "cargo clippy -- -D warnings"
  }
}

Write inputs and outputs on the turbo.json side to make caching work.

{
  "tasks": {
    "build": {
      "inputs": ["src/**", "Cargo.toml", "Cargo.lock"],
      "outputs": ["target/release/**"]
    }
  }
}
  • If you do not narrow down inputs, changes to unrelated files will invalidate the cache.
  • Specifying the entire target in outputs makes the artifacts huge. Specify only the necessary paths.
  • It doubles up with Cargo's own incremental cache. Decide which one to use before configuring.

Go has experimental native support. Enable futureFlags in turbo.json and list the modules in go.work. In this case, package.json is not needed on the Go package side, and the module path becomes the package identifier.

{
  "futureFlags": { "experimentalGoWorkspaces": true }
}

Since it is experimental, the behavior may change. Before adopting it, check the current status in the documentation above.

Confirm before finalizing

  • Are lockfiles other than pnpm (package-lock.json, yarn.lock) mixed in?
  • Are deployable apps not in packages, and shared libraries not in apps?
  • Internal dependencies are workspace:* is it set to?
  • Does each package have private and exports, and inherit the shared tsconfig?
  • Are responsibility packages not being reimplemented on the caller side?
  • Is the key in turbo.json tasks? Has it not been left as pipeline?
  • Are outputs, inputs, and env accurate? Is the cache not in a state where it hits incorrectly or is always invalidated?
  • Are dependency additions not being done by hand-editing package.json?
  • Is turbo not installed globally?