Tasks

Purpose and Scope

A Turborepo task is a script that Turborepo runs across the packages in a workspace. The reader problem this page solves is deciding how to describe repository workflows so turbo run can execute them in the right order, cache the right files, and keep local and CI behavior consistent. Instead of manually running workspace scripts one phase at a time, you register task names in the root turbo.json; Turborepo then finds matching package.json scripts in packages and schedules them through its package and task graph.

Sources: apps/docs/content/docs/crafting-your-repository/configuring-tasks.mdx, apps/docs/content/docs/crafting-your-repository/running-tasks.mdx

The important mental model is that task configuration is declarative. turbo.json explains relationships, outputs, inputs, and execution constraints, while each package keeps the actual command in its own package.json script. That separation lets a repository use a single workflow name such as build, test, lint, or dev even when different packages implement the script differently. Turborepo can then parallelize work whenever dependency rules allow it, which is the reason turbo run lint build test can be faster than serial workspace command chains.

Sources: apps/docs/content/docs/crafting-your-repository/configuring-tasks.mdx

Relevant Source Files

  • apps/docs/content/docs/crafting-your-repository/configuring-tasks.mdx — Defines tasks as scripts, introduces the root turbo.json, shows the tasks object, explains dependsOn, and motivates outputs for caching.
  • apps/docs/content/docs/crafting-your-repository/running-tasks.mdx — Explains how to execute registered tasks through root package.json scripts, global turbo, automatic package scoping, and filters.
  • apps/docs/content/docs/guides/ci-vendors/github-actions.mdx — Provides a concrete CI example with root scripts, turbo.json task definitions, outputs, dependsOn, and optional Remote Cache environment variables.
  • apps/docs/content/docs/guides/ci-vendors/vercel.mdx — Describes Vercel’s zero-config Turborepo integration and automatic Remote Cache setup for deployments.
  • apps/docs/content/blog/free-vercel-remote-cache.mdx — Explains Remote Caching as a distributed layer that prevents developers and CI from repeating the same work and lists TURBO_TOKEN and TURBO_TEAM setup for non-Vercel CI.
  • apps/docs/content/blog/joining-vercel.mdx — Records the project milestone that the CLI became open source and that Vercel provides zero-config remote caching.

Core Primitives

The root primitive is the tasks object in turbo.json. Each key is a task name that can be requested with turbo run, and Turborepo searches packages for scripts with the same name. A minimal build task can be declared as an empty object, but the docs warn that this is usually incomplete because Turborepo would run all matching build scripts in parallel and would not know which file outputs should be cached. A useful task definition normally also describes dependency order and output artifacts.

Sources: apps/docs/content/docs/crafting-your-repository/configuring-tasks.mdx

./turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "test": {
      "dependsOn": ["^build"]
    }
  }
}

dependsOn defines ordering constraints between tasks. The most common pattern is "^build", where the caret microsyntax means that the same task should run first in package dependencies before it runs in the dependent package. This is how a library build can complete before an app build that consumes it. Without this relationship, Turborepo is free to parallelize all matching scripts; with it, Turborepo still parallelizes everything it safely can, but it respects the dependency-first order required by the package graph.

Sources: apps/docs/content/docs/crafting-your-repository/configuring-tasks.mdx

outputs tells Turborepo which files a task produces and therefore which artifacts can be cached and restored. In the GitHub Actions guide, a Next.js-oriented build task caches .next/** while excluding .next/cache/** and .next/dev/**, and it also lists another output directory. That example matters because it shows the contract: the task command remains in package.json, but turbo.json names the build artifacts that make cache hits useful and predictable in local development and CI.

Sources: apps/docs/content/docs/guides/ci-vendors/github-actions.mdx

How turbo run Executes Scripts

After tasks are registered, the normal entry point is turbo run <task...>. The running-tasks guide recommends placing frequent workflows in the root package.json, not in package-level package.json files, because package-level turbo scripts can recursively call Turborepo. Root scripts become the stable interface for developers and CI, while package scripts remain the implementation details. The docs also note that turbo is an alias for turbo run, but recommend spelling out turbo run in root scripts and CI to avoid future subcommand collisions.

Sources: apps/docs/content/docs/crafting-your-repository/running-tasks.mdx

./package.json
{
  "scripts": {
    "dev": "turbo run dev",
    "build": "turbo run build",
    "test": "turbo run test",
    "lint": "turbo run lint"
  }
}

Developers can call those root scripts with the package manager that owns the workspace: pnpm dev, yarn dev, npm run dev, or bun run dev. This keeps Turborepo integrated with the repository’s existing package-manager workflow rather than requiring every contributor to remember the full CLI invocation. For one-off local work, a globally installed turbo can be run directly. When executed from inside a package directory, global turbo automatically scopes commands to that package’s position in the package graph unless a filter is provided.

Sources: apps/docs/content/docs/crafting-your-repository/running-tasks.mdx

Filters are the escape hatch when the requested task set should be narrower than the whole repository or the current package scope. The running-tasks guide calls out filtering by package, directory, source-control changes, and related selectors. A common workflow is keeping a general build script as turbo build or turbo run build, then using a package filter for focused work such as turbo build --filter=@repo/ui. This preserves the global task definition while letting developers ask for only the affected or relevant package subset.

Sources: apps/docs/content/docs/crafting-your-repository/running-tasks.mdx

Persistent Tasks and Development Servers

A persistent task is a long-running task, such as a development server or watcher, that is expected not to exit on its own. In Turborepo configuration, persistent tasks are marked with "persistent": true. Because they do not complete, they cannot be used as prerequisites in the task graph: a task that depends on a never-ending server would never become runnable. The practical guidance is to reserve persistent tasks for commands like dev that provide an interactive process, and keep build, lint, and test tasks finite so they can participate in dependency ordering and caching.

Sources: apps/docs/content/docs/crafting-your-repository/configuring-tasks.mdx, apps/docs/content/docs/crafting-your-repository/running-tasks.mdx

./turbo.json
{
  "tasks": {
    "dev": {
      "persistent": true,
      "cache": false
    }
  }
}

For watch-style development, distinguish between tools that are dependency-aware and tools that are not. If a script’s own watcher, such as a framework dev server, can detect changes in dependency packages, run that script directly through a persistent task and let the tool handle reloads. If the tool cannot notice dependency changes, the first-party watch reference recommends marking the task interruptible: true so Turborepo can restart it when relevant changes are detected. This keeps development servers compatible with monorepo changes without treating them like normal build steps.

Sources: apps/docs/content/docs/crafting-your-repository/running-tasks.mdx

Caching, Outputs, and CI Behavior

Caching only becomes valuable when task definitions describe the work precisely enough for Turborepo to decide whether an existing result can be reused. The configuring guide frames outputs as one of the missing pieces in a naive task definition, and the CI examples show why: a build task with declared outputs can restore artifacts instead of rebuilding them. Remote Caching extends that behavior beyond one machine, acting as a distributed cache so developers and CI do not repeat the same work after an equivalent task has already produced artifacts.

Sources: apps/docs/content/docs/crafting-your-repository/configuring-tasks.mdx, apps/docs/content/blog/free-vercel-remote-cache.mdx

In GitHub Actions, the documented pattern is to run root package scripts such as pnpm build and pnpm test, where those scripts call turbo run build and turbo run test. The sample workflow checks out code, installs the package manager, sets up Node.js with package-manager caching, installs dependencies, then invokes the root scripts. Its turbo.json defines build with outputs and dependsOn: ["^build"], while test depends on ^build. That sequence illustrates how local task configuration becomes the CI contract.

Sources: apps/docs/content/docs/guides/ci-vendors/github-actions.mdx

Remote Cache authentication differs by platform. Vercel automatically configures Turborepo projects to use Vercel Remote Cache, and the blog announcement describes Vercel Remote Cache as free and zero-configuration for repositories linked to Vercel. On other CI providers, the documented setup is to provide TURBO_TOKEN and TURBO_TEAM; the GitHub Actions guide shows these as optional environment variables that can be uncommented in the job. Locally, users can start with npx turbo login and npx turbo link to connect the repository.

Sources: apps/docs/content/docs/guides/ci-vendors/vercel.mdx, apps/docs/content/blog/free-vercel-remote-cache.mdx, apps/docs/content/blog/joining-vercel.mdx

Terminal
npx turbo login
npx turbo link

Compact Task Reference

ConceptConfiguration or commandBehavior
Register a tasktasks.<name> in turbo.jsonMakes <name> available to turbo run and matches package scripts with the same name.
Run tasksturbo run build testExecutes requested tasks across matching packages and parallelizes safe work.
Dependency taskdependsOn: ["^build"]Runs build in dependency packages before the dependent package’s task.
Cache artifactsoutputs: ["dist/**"]Declares task outputs that Turborepo can cache and restore.
Root script"build": "turbo run build"Provides a package-manager-friendly entry point for frequent workflows.
Persistent taskpersistent: trueMarks a long-running process that should not be used as a dependency prerequisite.
Focused execution--filter=@repo/uiNarrows task execution to selected packages or scopes.
Remote Cache authTURBO_TOKEN, TURBO_TEAMAuthenticates non-Vercel CI providers to Vercel Remote Cache.

Start by registering only the workflows your repository actually needs, then add dependency order and outputs before relying on cache behavior. Prefer root package.json scripts for repeatable developer and CI commands, use filters for focused local work, and treat persistent dev tasks separately from finite build or test tasks. After the task model is stable, continue with configuration details, caching, and CI vendor setup so the same turbo run workflow remains predictable on every machine.

Sources: apps/docs/content/docs/crafting-your-repository/configuring-tasks.mdx, apps/docs/content/docs/crafting-your-repository/running-tasks.mdx, apps/docs/content/docs/guides/ci-vendors/github-actions.mdx