Hey! These docs are for version 2.14, which is no longer officially supported. Click here for the latest version, 2.18!

Most goals require metadata about your code. For example, to run a test, you need to know about all the transitive dependencies of that test. You may also want to set a timeout on that test.

_Targets_ are an _addressable_ set of metadata describing your code.

For example:

  • `shell_source` and `python_test` describe first-party code

  • `python_requirement` describes third-party requirements

  • `pex_binary` and `archive` describe artifacts you'd like Pants to build

To reduce boilerplate, some targets also generate other targets:

  • `python_tests` -> `python_test`

  • `shell_sources` -> `shell_source`

  • `go_mod` -> `go_third_party_package`

# BUILD files

Targets are defined in files with the name `BUILD`. For example:

Each target type has different _fields_, or individual metadata values. Run `./pants help $target` to see which fields a particular target type has, e.g. `./pants help file`. Most fields are optional and use sensible defaults.

All target types have a `name` field, which is used to identify the target. Target names must be unique within a directory.

You can autoformat `BUILD` files by enabling a `BUILD` file formatter by adding it to `[GLOBAL].backend_packages` in `pants.toml` (such as `pants.backend.build_files.fmt.black` [or others](🔗)). Then to format, run `./pants fmt '**/BUILD'` or `./pants fmt ::` (formats everything).

# Target addresses

A target is identified by its unique address, in the form `path/to/dir:name`. The above example has the addresses `helloworld/greet:tests` and `helloworld/greet:bin`.

Addresses are used in the `dependencies` field to depend on other targets. Addresses can also be used as command-line arguments, such as `./pants fmt path/to:tgt`.

(Both "generated targets" and "parametrized targets" have a variant of this syntax; see the below sections.)

Default for the `name` field

The `name` field defaults to the directory name. So, this target has the address `helloworld/greet:greet`.

You can refer to this target with either `helloworld/greet:greet` or the abbreviated form `helloworld/greet`.

Use `//:tgt` for the root of your repository

Addressed defined in the `BUILD` file at the root of your repository are prefixed with `//`, e.g. `//:my_tgt`.

# `source` and `sources` field

Targets like `python_test` and `resource` have a `source: str` field, while target generators like `python_tests` and `resources` have a `sources: list[str]` field. This determines which source files belong to the target.

Values are relative to the BUILD file's directory. Sources must be in or below this directory, i.e. `../` is not allowed.

The `sources` field also supports `_` and `**` as globs. To exclude a file or glob, prefix with `!`. For example, `["_.py", "!exclude_*.py"]` will include `f.py` but not `exclude_me.py`.

Be careful with overlapping `source` fields

It's legal to include the same file in the `source` / `sources` field for multiple targets.

When would you do this? Sometimes you may have conflicting metadata for the same source file, such as wanting to check that a Shell test works with multiple shells. Normally, you should prefer Pants's `parametrize` mechanism to do this. See the below section "Parametrizing Targets".

Often, however, it is not intentional when multiple targets own the same file. For example, this often happens when using `**` globs, like this:

Including the same file in the `source` / `sources` field for multiple targets can result in two confusing behaviors:

  • File arguments will run over all owning targets, e.g. `./pants test path/to/test.ext` would run both test targets as two separate subprocesses, even though you might only expect a single subprocess.

  • Pants will sometimes no longer be able to infer dependencies on this file because it cannot disambiguate which of the targets you want to use. You must use explicit dependencies instead. (For some blessed fields, like the `resolve` field, if the targets have different values, then there will not be ambiguity.)

You can run `./pants list path/to/file.ext` to see all "owning" targets to check if >1 target has the file in its `source` field.

# `dependencies` field

A target's dependencies determines which other first-party code and third-party requirements to include when building the target.

Usually, you leave off the `dependencies` field thanks to _dependency inference_. Pants will read your import statements and map those imports back to your first-party code and your third-party requirements. You can run `./pants dependencies path/to:target` to see what dependencies Pants infers.

However, dependency inference cannot infer everything, such as dependencies on `resource` and `file` targets.

To add an explicit dependency, add the target's address to the `dependencies` field. This augments any dependencies that were inferred.

You only need to declare direct dependencies. Pants will pull in _transitive dependencies_—i.e. the dependencies of your dependencies—for you.

Relative addresses, `:tgt`

When depending on a target defined in the same BUILD file, you can simply use `:tgt_name`, rather than `helloworld/greet:tgt_name`, for example.

Addresses for generated targets also support relative addresses in the `dependencies` field, as explained in the "Target Generation" section below.

Ignore dependencies with `!` and `!!`

If you don't like that Pants inferred a certain dependency—as reported by [`./pants dependencies path/to:tgt`](🔗)—tell Pants to ignore it with `!`:

You can use the prefix `!!` to transitively exclude a dependency, meaning that even if a target's dependencies include the bad dependency, the final result will not include the value.

Transitive excludes can only be used in target types that conventionally are not dependend upon by other targets, such as `pex_binary` and `python_test` / `python_tests`. This is meant to limit confusion, as using `!!` in something like a `python_source` / `python_sources` target could result in surprising behavior for everything that depends on it. (Pants will print a helpful error when using `!!` when it's not legal.)

# Field default values

As mentioned above in [BUILD files](🔗), most fields use sensible defaults. And for specific cases it is easy to provide some other value to a specific target. The issue is if you want to apply a specific non-default value for a field on many targets. This can get unwieldy, error prone and hard to maintain. Enter `__defaults__`.

Default field values per target are set using the `__defaults__` BUILD file symbol, and apply to the current subtree.

The defaults are provided as a dictionary mapping targets to the default field values. Multiple targets may share the same set of default field values, when grouped together in parenthesis (as a Python tuple).

Use the `all` keyword argument to provide default field values that should apply to all targets.

The `extend=True` keyword argument allows to add to any existing default field values set by a previous `__defaults__` call rather than replacing them.

Default fields and values are validated against their target types, except when provided using the `all` keyword, in which case only values for fields applicable to each target are validated.

This means, that it is legal to provide a default value for `all` targets, even if it is only a subset of targets that actually supports that particular field.


Subdirectories may override defaults from a parent BUILD file:

Use the `extend=True` keyword to update defaults rather than replace them, for any given target.

To reset any modified defaults, simply override with the empty dict:

# Target generation

To reduce boilerplate, Pants provides target types that generate other targets. For example:

  • `files` -> `file`

  • `python_tests` -> `python_test`

  • `go_mod` -> `go_third_party_package`

Usually, prefer these target generators. [`./pants tailor ::`](🔗) will automatically add them for you.

Run `./pants help targets` to see how the target determines what to generate. Targets for first-party code, like `resources` and `python_tests`, will generate one target for each file in their `sources` field.

(Usually, you can leave off the `sources` field. When possible, it defaults to all relevant files in the current directory.)

Typically, fields declared in the target generator will be inherited by each generated target. For example, if you set `timeout=120` in a `python_tests` target, each generated `python_test` target will have `timeout=120`. You can instead use the `overrides` field for more granular metadata:

Field default values for generated targets

[Default field values](🔗) apply to target generators, _not_ to generated targets. For example, if you have:

Then the default `timeout` value will only apply to the "special" `python_test`, not to any of the targets generated by the `python_tests` target.

To specify defaults for both generated and manually-written instances of a target, you must list the target generator in your `__defaults__` as well:

The address for generated targets depends if the generated target is for first-party code or not:

Generated target typeGenerated address syntax
First-party, e.g. `python_source` and `file``path/to/file.ext:tgt_generator` Example: `src/py/app.py:lib` The address always starts with the path to the file. If the file lives in the same directory as the target generator and the target generator left off the `name` field, you can use just the file path. For example, `src/py/app.py` (without the `:lib` suffix). If the file lives in a subdirectory of the target generator, the suffix will look like `../tgt_generator`. For example, `src/py/subdir/f.py:../lib`, where the target generator is `src/py:lib`. With the `dependencies` field, you can use relative addresses by prefixing the path with `./`, so long as the path is in the same directory or below the current BUILD file. For example, `./app.py:lib` rather than `src/py/app.py:lib`.
All other targets, e.g. `go_third_party_package``path/to:tgt_generator#generated_name` Example: `3rdparty/py:reqs#django` Run `./pants help $target_type` on the target generator to see how it sets the generated name. For example, `go_mod` uses the Go package's name. If the target generator left off the `name` field, you can leave it off for the generated address too, e.g. `3rdparty/py#django` (without the `:reqs` portion). With the `dependencies` field, you can use relative addresses to reference generated targets in the same BUILD file, e.g. `:generator#generated_name` instead of `src/py:generated#generated_name`. If the target generator uses the default `name`, you can simply use `#generated_name`.

Run [`./pants list dir:`](🔗) in the directory of the target generator to see all generated target addresses, and [`./pants peek dir:`](🔗) to see all their metadata.

You can use the address for the target generator as an alias for all of its generated targets. For example, if you have the `files` target `assets:logos`, adding `dependencies=["assets:logos"]`to another target will add a dependency on each generated `file` target. Likewise, if you have a `python_tests` target `project:tests`, then `./pants test project:tests` will run on each generated `python_test` target.

Tip: one BUILD file per directory

Target generation means that it is technically possible to put everything in a single BUILD file.

However, we've found that it usually scales much better to use a single BUILD file per directory. Even if you start with using the defaults for everything, projects usually need to change some metadata over time, like adding a `timeout` to a test file or adding `dependencies` on resources.

It's useful for metadata to be as fine-grained as feasible, such as by using the `overrides` field to only change the files you need to. Fine-grained metadata is key to having smaller cache keys (resulting in more cache hits), and allows you to more accurately reflect the status of your project. We have found that using one BUILD file per directory encourages fine-grained metadata by defining the metadata adjacent to where the code lives.

[`./pants tailor ::`](🔗) will automatically create targets that only apply metadata for the directory.

# Parametrizing targets

It can be useful to create multiple targets describing the same entity, each with different metadata. For example:

  • Run the same tests with different interpreter constraints, e.g. Python 2 vs Python 3.

  • Declare that a file should work with multiple "resolves" (lockfiles).

The `parametrize` builtin creates a distinct target per parametrized field value. All values other than the parametrized field(s) are the same for each target. For example:

If multiple fields are parametrized, a target will be created for each value in the Cartesian product, with `,` as the delimiter in the address. See the next example.

If the field value is not a string—or it is a string but includes spaces—you can give it an alias, like the `interpreter_constraints` field below:

The targets' addresses will have `@key=value` at the end, as shown above. Run [`./pants list dir:`](🔗) in the directory of the parametrized target to see all parametrized target addresses, and [`./pants peek dir:`](🔗) to see all their metadata.

Generally, you can use the address without the `@` suffix as an alias to all the parametrized targets. For example, `./pants test example:tests` will run all the targets in parallel. Use the more precise address if you only want to use one parameter value, e.g. `./pants test example:tests@shell=bash`.

Parametrization can be combined with target generation. The `@key=value` will be added to the end of the address for each generated target. For example:

You can combine `parametrize` with the ` overrides` field to set more granular metadata for generated targets: