0.3.7 Aliases

recommended

alias() gives an existing target a stable second label. It does not create another implementation or copy the underlying files. Other packages can depend on that handle even if the real target later moves, gets renamed, or already sits behind a long label.1

alias(
    name = "my_lib",
    actual = "//path/to/real:lib",
)

In the example above, other targets can depend on //path/to:my_lib instead of //path/to/real:lib.1 The visible label and the underlying target are different names that lead to the same implementation.1

The Attributes To Notice

The syntax is small. name gives the alias its own label in the current package, and actual points at the target it redirects to.1,2 An alias can also declare its own visibility, so the access-control rules from 0.2.4 Visibility still matter when you expose a target under an alternate name.1,2

Why deprecation Does Not Mark The Old Name

The alias signature accepts the common deprecation attribute, but do not use it to migrate callers away from an old alias.2 The generic attribute normally warns cross-package dependents,3 but alias dependency checks read deprecation metadata from the resolved actual target rather than from the alias.4

Wrong behavior
alias(
    name = "old_lib",
    actual = "//path/to/real:lib",
    deprecation = "Use //path/to/real:lib instead of //path/to:old_lib",
)

The alias still resolves, but targets depending on //path/to:old_lib do not get that message. Bazel may print it when the alias itself is requested as a top-level target, but that does not provide the dependency warning a rename needs. This behavior is tracked in bazelbuild/bazel#5802, which was closed without a fix, and remains visible in Bazel 9.1's alias-resolution path.4

Treat an alias as a silent compatibility label. Track or query remaining uses separately, migrate them, and only then remove the alias.

Why This Rule Exists

The value of alias() is indirection. If a package wants one stable public label while the real implementation target changes over time, an alias keeps consumers decoupled from that internal churn.1 That is why it helps with renames, refactors, and package APIs that want a cleaner public entry point than the underlying target path.1

The separate file-collection case is covered in 0.3.6 filegroup Rule.1

If a package does not naturally have an eponymous default target, alias() can also create one.5 That connects back to the shorthand rules in 0.2.2 Syntactic Sugar & Relative Labels: one label stands in for another target.5

extra

A Legacy Pattern You May Still See

During Bzlmod migration, alias() replaces old bind() entries from WORKSPACE.6 Instead of keeping dependents on //external:openssl, you define a normal alias in a regular package and move callers to that package-local label.6

alias(
    name = "openssl",
    actual = "@my-ssl//src:openssl-lib",
)
key takeaway

An alias is a stable label that points at an existing target. When you see alias(), read it as a small indirection layer in the target graph: consumers depend on the alias name, and the alias forwards them to the real thing. During a rename, keep the old alias only as a temporary compatibility label and track migration separately — its own deprecation message does not warn dependent targets.1,4

Check your understanding · 2 questions

1.What does alias() actually create in the Bazel build graph?

Select one answer

2.True or false: when and how alias() is used.

Choose True or False for each sentence

alias() can declare its own visibility, independent of the underlying target's visibility.
When the actual target in an alias() is renamed or moved, all consumers that reference the alias must update their BUILD files.
alias() can be used to create an eponymous default target when no natural one exists in a package.
The Bzlmod migration guide recommends alias() as a replacement for legacy bind() entries from WORKSPACE.
0 of 2 answered

Footnotes

  1. Ultimate Monorepo and Bazel for Building Apps at Scale — alias as redirect/pointer, name and actual, optional visibility, and stable-name/refactor use cases ↩1 ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9

  2. General Rules — alias signature lists deprecation among common attributes, while name and actual are the rule-specific arguments ↩1 ↩2 ↩3

  3. Common definitions — deprecation is a string warning with no build effect. Cross-package dependents warn, but same-package and deprecated-to-deprecated edges do not ↩

  4. Bazel core repository map — issue #5802 reproduces the missing dependency warning and was closed without a fix. Bazel 9.1's AliasProvider and ConfiguredTargetAndData show why dependency validation observes the resolved target, while TargetPatternPhaseFunction checks the directly requested top-level target ↩1 ↩2 ↩3

  5. Bazel Training 101 (Part 9): Packages, Rules, Targets, and Labels — using alias() to create a package default target when no natural eponymous target exists ↩1 ↩2

  6. Bzlmod Migration Guide — replacing legacy bind() entries with a normal alias() target in a regular package ↩1 ↩2