Targets and BUILD files

Attaching metadata to your code.

Some build work, such as counting lines of code, needs only information found in source files, and doesn't require any other data.

Other work may require more information about the source files. For example, to run a test you need to know about all the transitive dependencies of that test.

This extra information lives in entities called targets. A target is a collection of source files, with some extra metadata attached.

BUILD files

Target information lives in files with the name BUILD. For example:

    name = 'greet',
    sources = ['*.py', '!*_test.py'],
    dependencies = [
    compatibility = ">=3.6",

Let's break this down:

  • python_library: The target's type. In this case, a library containing Python code.
  • name = 'greet': The name of the target, which defaults to the name of the directory but may be explicitly specified. Target names must be unique within a directory.
  • sources = ['*.py', '!*_test.py']: The source files belonging to the target.
  • dependencies = [...]: The other targets on which this target directly depends.

Some target types are built in, but most are provided by backends. For example, the python_library target type is provided by the pants.backend.python backend.

All target types have a name field, and almost all have sources and dependencies fields. Specific target types will have extra fields, as needed. For example, the python_binary target has an entry_point field that points to the main module for the binary.

Target addresses

A target is identified by its address. A target address has the form path/to/directory:name. For example, the target in the example above has the address helloworld/greet:greet.

A target's dependencies field references the targets it depends on using their addresses. Addresses are also sometimes used as command-line arguments.

Addresses are globally unique, which is guaranteed by the fact that target names must be unique within a BUILD file.


Address Abbreviation

If the target name is the same as the name of the directory containing it, then you can omit the target name. For example, helloworld/greet is an abbreviated form of helloworld/greet:greet.


Almost all targets have a sources field, which determines which source files belong to the target.

The value of the sources field is a list of names and/or glob patterns, relative to the BUILD file's directory. Sources must be in or below this directory, i.e., patterns containing ../ are not allowed.

A ! prefix excludes matching files that would otherwise be included. For example, ['*.py', '!exclude_*.py'] will include foo.py but exclude exclude_bar.py.

While it is not recommended for a target to own source files in subdirectories (with the 1:1:1 method preferred), it is possible with the following syntax: sources=['**/*.py'], where ** is a recursive glob that matches zero or more directories. This replaces the pre-v1.25 syntax which used rglobs to indicate that a glob was recursive.


Almost all targets have a dependencies field, which determines the direct dependencies of the target.

The value of the dependencies field is a list of addresses of other targets. If code in target A directly depends on code in target B (e.g., by importing a symbol from B) then A should declare a dependency on B. There is no need to declare indirect dependencies (that is, transitive dependencies of your direct dependencies).


Dependency Shorthand

If you depend on another target in the same BUILD file, you can omit the address and just use the name. For example, for dependencies listed in helloworld/greet, the string :greetings is shorthand helloworld/greet:greetings`.

Default field values

To cut down on boilerplate:

  • A target's name defaults to the name of the directory it's in.
  • Some target types will have a sensible default for the sources field.
    For example, the default value for the sources field of a python_library target is ['*.py', '!*_test.py', '!test_*.py', '!conftest.py']. I.e., "all Python source files in this target's directory, that aren't test-related".

So, for example, the target above might be rewritten more succinctly as:

    dependencies = [
    compatibility = ">=3.6",

The build graph

The set of targets in a repo form the build graph. The vertices in this graph are the targets, and the (directed) edges are the dependencies. The build graph must not contain directed cycles, i.e., it must form a DAG (a Directed Acyclic Graph).

Target granularity

A target's sources can be as fine-grained as a single file, or as course-grained as an entire tree of files. Target granularity has implications for invalidation and caching, and therefore for performance.

Different granularities work best for different scenarios. But we've found that having one library and/or one test target per directory often tends to work well in practice. The default sources values for various target types reflect this.


Upcoming feature: dependency inference

We are working on a feature where Pants understands your Python import statements and will automatically add them to the dependencies field for your targets. This means that you will be able to leave off dependencies in most of your BUILD files.