turbo query

Purpose and Scope

turbo query is Turborepo’s repository-inspection command for teams that need more detail than a task run, package list, or browser visualization can provide. The command exposes a GraphQL interface into the monorepo model, so you can ask targeted questions about packages, tasks, dependency relationships, and affected work. It is intended for diagnosis and automation: use it when you need to understand why work is selected, which packages match a task shape, or which parts of the repository are creating broad invalidation.

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

The command belongs with Turborepo’s other repository-understanding tools. turbo devtools gives a browser-based visualization of the package graph, turbo ls lists packages and supports filters, and turbo run without task names reports available tasks and the packages where they are defined. turbo query goes deeper by letting you formulate structured GraphQL queries, returning JSON-shaped responses that can be read by humans or consumed by CI scripts.

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

This page focuses on the command reference concerns that matter in practice: how to select packages and tasks, how affected queries fit CI, what output shape to expect, and how to migrate skip logic away from turbo-ignore. It also ties the command back to package graph, task graph, caching, and development workflow concepts, because query results are most useful when you understand the model being queried rather than treating the command as a standalone reporting tool.

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

Relevant Source Files

  • apps/docs/content/docs/crafting-your-repository/understanding-your-repository.mdx - Defines the turbo query guide entry, explains that the command provides a GraphQL interface starting in Turborepo 2.2.0, and shows concrete package and affected-package queries.
  • apps/docs/content/docs/crafting-your-repository/constructing-ci.mdx - Places query-driven affected detection in the CI workflow alongside Remote Caching, task filtering, and the --affected flag.
  • apps/docs/content/docs/crafting-your-repository/configuring-tasks.mdx - Defines tasks as scripts registered in turbo.json, explains dependsOn, and provides the task-graph vocabulary that query users inspect.
  • apps/docs/content/docs/crafting-your-repository/caching.mdx - Explains cache fingerprints, deterministic task assumptions, and cache misses, which are common reasons to inspect invalidation with turbo query.
  • apps/docs/content/docs/crafting-your-repository/creating-an-internal-package.mdx - Explains internal packages and the package graph relationships derived from package.json dependencies.
  • apps/docs/content/docs/crafting-your-repository/developing-applications.mdx - Shows package filtering for development tasks and long-lived dev task configuration, useful context for selecting task entry points.

Command Model and Output

At its core, turbo query evaluates a GraphQL request against Turborepo’s understanding of the repository. The documentation example queries packages(filter: { has: { field: TASK_NAME, value: "build"}}) and requests items { name }. The response is a JSON object with a top-level data field, then the requested GraphQL field, then items. In the example, packages named //, docs, and web are returned because those packages expose the requested task.

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

Terminal
turbo query "query { packages(filter: { has: { field: TASK_NAME, value: \"build\"}}) { items { name } } }"
Output shape
{
  "data": {
    "packages": {
      "items": [
        { "name": "//" },
        { "name": "docs" },
        { "name": "web" }
      ]
    }
  }
}

Because the response follows the requested GraphQL selection set, the output format is most useful when you ask only for fields your automation needs. For a local diagnosis, a short items { name } query is easy to read. For CI, include the fields that explain why a package is affected so a skipped or executed job can print a meaningful reason. For scripts, treat the response as structured JSON instead of scraping terminal prose.

Sources: apps/docs/content/docs/crafting-your-repository/understanding-your-repository.mdx, apps/docs/content/docs/crafting-your-repository/constructing-ci.mdx

Package and Task Selection

Package selection in turbo query builds on Turborepo’s package graph. Internal packages are discovered through workspace package metadata and dependency declarations in package.json; those relationships let Turborepo know which applications depend on shared libraries. When a query asks for packages with a task, direct dependents, or affected status, it is querying that graph rather than scanning random directories. This is why accurate workspace configuration and package names are important before the command can provide useful answers.

Sources: apps/docs/content/docs/crafting-your-repository/creating-an-internal-package.mdx, apps/docs/content/docs/crafting-your-repository/understanding-your-repository.mdx

Task selection uses the same task vocabulary as turbo run. A task is a package script that Turborepo can run when it is registered in the root turbo.json tasks object. The configuring-tasks guide explains that each key in tasks can be executed by turbo run, and Turborepo searches packages for matching package.json scripts. Therefore a query such as “packages that have a build task” is really asking which packages participate in that configured task surface.

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

The docs also show a diagnostic query for packages whose direct dependent count is greater than ten. That use case is important for cache troubleshooting: a small shared package imported throughout the repository can cause many downstream tasks to become invalidated. If turbo query identifies a package like utils as a high-fanout dependency, the next design step may be to split it into smaller packages so unrelated changes no longer invalidate as much of the graph.

Sources: apps/docs/content/docs/crafting-your-repository/understanding-your-repository.mdx, apps/docs/content/docs/crafting-your-repository/caching.mdx

Terminal
turbo query "query { packages(filter: { greaterThan: { field: DIRECT_DEPENDENT_COUNT, value: 10 } }) { items { name } } }"

Affected Queries in CI

Affected queries connect repository inspection to CI efficiency. The constructing-CI guide explains that CI pipelines can run the same tasks registered in turbo.json, use Remote Caching with TURBO_TOKEN and TURBO_TEAM, and filter work by package, directory, Git history, or --affected. turbo query complements that flow by showing which packages are affected between two revisions and why they were invalidated, which is especially useful when a pipeline is doing more work than expected.

Sources: apps/docs/content/docs/crafting-your-repository/constructing-ci.mdx, apps/docs/content/docs/crafting-your-repository/understanding-your-repository.mdx

A representative GraphQL query is affectedPackages(base: "HEAD^", head: "HEAD") { items { reason { __typename } } }. The documented response includes reasons such as FileChanged for a package changed directly and DependencyChanged for packages invalidated because something they depend on changed. This distinction is the key diagnostic value: a package may be selected not because its own files changed, but because the package graph says one of its dependencies changed.

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

Terminal
turbo query "query { affectedPackages(base: \"HEAD^\", head: \"HEAD\") { items { name reason { __typename } } } }"

Use affected output in CI as an explanation layer, not only as a yes-or-no gate. If a build is unexpectedly running, print the package names and reason types so maintainers can decide whether to adjust package boundaries, task inputs, or filters. The CI guide also warns that Git-history-based filtering requires history to be available on the machine, so shallow clones can make affected-style decisions unreliable until the CI checkout is configured with sufficient history.

Sources: apps/docs/content/docs/crafting-your-repository/constructing-ci.mdx, apps/docs/content/docs/crafting-your-repository/understanding-your-repository.mdx

Migration from turbo-ignore

turbo-ignore was historically used to decide whether a package or its dependencies changed before running CI work. The current guidance is to move skip-build decisions to turbo query affected, because it provides more precise task-level change detection and uses the same repository model as Turborepo itself. In practice, that means replacing a package-only skip command with a query or affected workflow that can report both selected packages and invalidation reasons.

Sources: apps/docs/content/docs/crafting-your-repository/constructing-ci.mdx, apps/docs/content/docs/crafting-your-repository/understanding-your-repository.mdx

A migration should start by writing down what the old skip step protected: a deployment for one workspace, a test suite for a package subtree, or an expensive build for a shared library. Next, model that decision using package names, task names, and Git base/head revisions. Then run turbo query in CI and compare its selected packages with the old turbo-ignore decision for several pull requests. Once the output matches intent, remove the deprecated package and keep the query output in logs for auditability.

Sources: apps/docs/content/docs/crafting-your-repository/constructing-ci.mdx, apps/docs/content/docs/crafting-your-repository/understanding-your-repository.mdx

Compact Reference

AreaReferenceNotes
Commandturbo query "query { ... }"Executes a GraphQL request against Turborepo’s repository model.
Package filtering examplepackages(filter: { has: { field: TASK_NAME, value: "build"}})Finds packages that define a matching task name.
High-fanout examplepackages(filter: { greaterThan: { field: DIRECT_DEPENDENT_COUNT, value: 10 } })Finds packages imported by many dependents, useful for cache-miss diagnosis.
Affected exampleaffectedPackages(base: "HEAD^", head: "HEAD")Compares two Git revisions and returns affected package items.
Reason fieldreason { __typename }Distinguishes direct file changes from dependency-driven invalidation.
OutputJSON GraphQL response with data and requested fieldsShape depends on the selection set.

For next steps, use turbo ls when you only need the package list, turbo run without tasks when you need available task names, and turbo devtools when graph visualization is easier than a query. Use turbo query when the question is specific enough to benefit from GraphQL or when CI needs a structured, machine-readable explanation of affected work.

Sources: apps/docs/content/docs/crafting-your-repository/understanding-your-repository.mdx, apps/docs/content/docs/crafting-your-repository/developing-applications.mdx