Skip to content
Vercel

Turborepo 2.10

Wednesday, June 24th, 2026
Anthony Shew
Name
Anthony Shew
X
@anthonysheww

Turborepo 2.10 improves day-to-day reliability in your repository:


Upgrade today by running npx @turbo/codemod migrate or get started with npx create-turbo@latest.

Terminal
# Use the automated upgrade CLI
pnpm dlx @turbo/codemod migrate

# Start a new repository
pnpm dlx create-turbo@latest
Terminal
# Use the automated upgrade CLI
yarn dlx @turbo/codemod migrate

# Start a new repository
yarn dlx create-turbo@latest
Terminal
# Use the automated upgrade CLI
npx @turbo/codemod migrate

# Start a new repository
npx create-turbo@latest
Terminal
# Use the automated upgrade CLI
bunx @turbo/codemod migrate

# Start a new repository
bunx create-turbo@latest

Install or update your Turborepo Agent Skill:

Terminal
# Install the Turborepo Agent Skill
pnpm dlx skills add vercel/turborepo

# Update the Turborepo Agent Skill
pnpm dlx skills update vercel/turborepo
Terminal
# Install the Turborepo Agent Skill
yarn dlx skills add vercel/turborepo

# Update the Turborepo Agent Skill
yarn dlx skills update vercel/turborepo
Terminal
# Install the Turborepo Agent Skill
npx skills add vercel/turborepo

# Update the Turborepo Agent Skill
npx skills update vercel/turborepo
Terminal
# Install the Turborepo Agent Skill
bunx skills add vercel/turborepo

# Update the Turborepo Agent Skill
bunx skills update vercel/turborepo

Graceful task shutdown

It's common for a repository to have cleanup steps when closing out a development environment. For example, flushing logs, terminating a Docker Compose script, or closing a background process.

In previous versions, Turborepo exited immediately when it received a SIGTERM or SIGINT signal, abruptly killing all of your tasks. A server wouldn't close its connections, a background process wouldn't get cleaned up, and you'd be left to sort out the mess yourself.

Now, Turborepo forwards Ctrl+C (or SIGINT/SIGTERM) to your tasks and waits for them to finish shutting down. Your signal handling code runs, cleanup finishes, and Turborepo exits after every task is done.

Terminal
 ~ turbo dev

 turbo 2.10.0

server:dev: cache bypass, force executing 57ef564a0dbdb237
server:dev:
server:dev: Server started...
server:dev: Handling request [GET] /
^C - Shutting down Turborepo tasks...Press CTRL+C again to exit forcefully.
server:dev: SIGINT received!
server:dev: Terminating database connection...
server:dev: Terminated database connection.

 Tasks:    1 successful, 1 total
Cached:    0 cached, 1 total
  Time:    3.6s

There's nothing to configure, and tasks without their own signal handling behave exactly as before.

Deferred input hashing

By default, Turborepo creates the hashes for all of your tasks right when turbo starts. Hashing up front lets Turborepo execute your Task Graph as fast as possible, since it can instantly know whether each task is a cache hit or miss.

But some file inputs aren't stable while the Task Graph is executing. An upstream task like codegen might change files after turbo has already hashed everything. Because task hashing happened too early, you might choose to turn off caching, or risk unexpected cache hits.

Starting with this release, you can use structured inputs objects to defer hashing until the right moment in the run. We're introducing two new task hashing primitives.

Just-in-Time task hashing

When you need to delay hashing for a specific task, use "mode": "jit". Postponing task hashing gives your task the freedom to edit file inputs after initial hashing and still hit cache for dependent tasks.

In the example below, the build task needs a generated GraphQL schema from a remote source:

turbo.json
{
  "tasks": {
    "codegen": {
      "cache": false,
    },
    "build": {
      "dependsOn": ["codegen"],
      "inputs": [
        "$TURBO_DEFAULT$",
        "!src/generated/**",
        {
          "mode": "jit",
          "globs": ["src/generated/**"],
        },
      ],
    },
  },
}

Because the GraphQL schema must be fetched, that task is uncacheable. The build task can still hit cache safely if the schema doesn't change. Just-in-Time hashing delays the task hash for build until after codegen has completed, ensuring that build's task hash uses the generated inputs.

Output-dependent task hashing

When you want the outputs of task dependencies to affect the hash of dependent tasks, use the dependencyOutputs mode. Output-dependent task hashing uses the outputs of a task dependency as file inputs to a dependent task.

For example, the following configuration can increase cache hit ratios for type checking in a TypeScript repository that emits type declaration files:

turbo.json
{
  "tasks": {
    "check-types": {
      "dependsOn": ["^check-types"],
      "outputs": ["dist/**"],
      "inputs": [
        "$TURBO_DEFAULT$",
        {
          "mode": "dependencyOutputs",
          "globs": ["dist/**/*.d.ts"],
          "from": ["^check-types"]
        }
      ]
    }
  }
}

This configuration uses the type declaration files in dist as inputs to a task dependent's hash, meaning task dependents will only miss cache when the package's interface changes. Updating internal logic or comments won't result in cache misses in dependencies, but changing the interface of an export will.

Visit the documentation to learn more.

Combine --affected and --filter

Previously, you couldn't use --affected and --filter at the same time. Now, you can.

Terminal
# Only run build for "web" if it's affected by changes
turbo run build --affected --filter=web

# Run affected packages, excluding "docs"
turbo run build --affected --filter=!docs

# List "my-app" only if it's affected
turbo query ls --affected --filter=my-app

The two flags intersect, so only the tasks that match both constraints run. To learn more, visit the documentation.

Local cache eviction

Turborepo saves its local cache into .turbo/cache, adding cache artifacts every time you run a cacheable task. This speeds up repeat runs, but the cache never stops growing.

Turborepo now supports automatic eviction through two opt-in configuration options in turbo.json. You can use either age-based eviction or size-based eviction:

turbo.json
{
  "cacheMaxAge": "7d",
  "cacheMaxSize": "10GB",
}

cacheMaxAge clears artifacts older than the limit. cacheMaxSize clears the oldest artifacts first once the cache passes the cap. Eviction runs in a background thread at the start of each turbo run, so it does not block tasks.

We expect to enable local cache eviction by default in Turborepo 3.0. Read more here.

All changes

Acknowledgments and community

Turborepo is the result of the combined work of all of its contributors, including our core team: Anthony and Tom.

We also thank everyone who contributed to this release of Turborepo: @adityasingh2400, @AndyBitz, @Balance8, @biru-codeastromer, @bitttttten, @bjormgyg, @christopherkindl, @dancrumb, @DependerKumarSoni, @eastgold15, @gioboa, @gwagjiug, @hack-313-ip, @haydenbleasel, @JRoy, @kitten, @marc-vercel, @markandrus, @maschwenk, @mattjoll, @mehulkar, @molebox, @mvanhorn, @Nsttt, @ognevny, @saiteja-madha, @sleitor, and @Wartijn.

Thank you for your continued support, feedback, and collaboration to make Turborepo your build tool of choice. To learn how to get involved, visit the Community page.