---
layout: documentation
title: Repository Rules
---
# Repository Rules

**Status: Experimental**. We may make breaking changes to the API, but we will
  announce them.

An [external repository](../external.md) is a rule that can be used only
in the `WORKSPACE` file and enables non-hermetic operation at the loading phase
of Bazel. Each external repository rule creates its own workspace, with its
own BUILD files and artifacts. They can be used to depend on third-party
libraries (such as Maven packaged libraries) but also to generate BUILD files
specific to the host Bazel is running on.

## Repository Rule creation

In a `.bzl` file, use the
[repository_rule](lib/globals.html#repository_rule) function to create a new
repository rule and store it in a global variable.

A custom repository rule can be used just like a native repository rule. It
has a mandatory `name` attribute and every target present in its build files
can be referred as `@<name>//package:target` where `<name>` is the value of the
`name` attribute.

The rule is loaded when you explicitly build it, or if it is a dependency of
the build. In this case, Bazel will execute its `implementation` function. This
function describe how to create the repository, its content and BUILD files.

## Attributes

An attribute is a rule argument, such as `url` or `sha256`. You must list
the attributes and their types when you define a repository rule.

```python
local_repository = repository_rule(
    implementation=_impl,
    local=True,
    attrs={"path": attr.string(mandatory=True)})
```

`name` attributes are implicitly defined for all `repository_rule`s.
To access an attribute, use `repository_ctx.attr.<attribute_name>`.
The name of a repository rule is accessible with `repository_ctx.name`.

If an attribute name starts with `_` it is private and users cannot set it.

## Implementation function

Every repository rule requires an `implementation` function. It contains the
actual logic of the rule and is executed strictly in the Loading Phase.

The function has exactly one input parameter, `repository_ctx`. The function
returns either `None` to signify that the rule is reproducible, or a dict with a
set of parameters for that rule that would turn that rule into a reproducible
one generating the same repository. For example, for a rule tracking a git
repository that would mean returning a specific commit identifier instead of a
floating branch that was originally specified.

The input parameter `repository_ctx` can be used to
access attribute values, and non-hermetic functions (finding a binary,
executing a binary, creating a file in the repository or downloading a file
from the Internet). See [the library](lib/repository_ctx.html) for more
context. Example:

```python
def _impl(repository_ctx):
  repository_ctx.symlink(repository_ctx.attr.path, "")

local_repository = repository_rule(
    implementation=_impl,
    ...)
```

## When is the implementation function executed?

If the repository is declared as `local` then change in a dependency
in the dependency graph (including the WORKSPACE file itself) will
cause an execution of the implementation function.

The implementation function can be _restarted_ if a dependency it
request is _missing_. The beginning of the implementation function
will be re-executed after the dependency has been resolved. To avoid
unnecessary restarts (which are expensive, as network access might
have to be repeated), label arguments are prefetched, provided all
label arguments can be resolved to an existing file. Note that resolving
a path from a string or a label that was constructed only during execution
of the function might still cause a restart.

Finally, for non-`local` repositories, only a change in the following
dependencies might cause a restart:

- `.bzl` files needed to define the repository rule.
- Declaration of the repository rule in the `WORKSPACE` file.
- Value of any environment variable declared with the `environ`
attribute of the
[`repository_rule`](https://docs.bazel.build/skylark/lib/globals.html#repository_rule)
function. The value of those environment variable can be enforced from
the command line with the
[`--action_env`](https://docs.bazel.build/command-line-reference.html#flag--action_env)
flag (but this flag will invalidate every action of the build).
- Content of any file used and referred to by a label (e.g.,
  `//mypkg:label.txt` not `mypkg/label.txt`).

## Examples

- [C++ auto-configured toolchain](https://github.com/bazelbuild/bazel/blob/ac29b78000afdb95afc7e97efd2b1299ebea4dac/tools/cpp/cc_configure.bzl#L288):
it uses a repository rule to automatically create the
C++ configuration files for Bazel by looking for the local C++ compiler, the
environment and the flags the C++ compiler supports.

- [Go repositories](https://github.com/bazelbuild/rules_go/blob/67bc217b6210a0922d76d252472b87e9a6118fdf/go/private/go_repositories.bzl#L195)
  uses several `repository_rule` to defines the list of dependencies
  needed to use the Go rules.

- [maven_jar](https://github.com/bazelbuild/bazel/blob/master/tools/build_defs/repo/maven_rules.bzl#L281)
  is a reimplementation of the native `maven_jar` rule using the
  `maven` tool.
