Bazel Book

package() Function

recommended

A BUILD file already defines a package boundary, as described in 0.1.3 Package. The package() function does something different: it declares metadata that applies to the rules in that package. In Level 0, the two parameters worth remembering are default_visibility and default_testonly1.

Package-Wide Defaults

package() may appear at most once in a BUILD file, and if you use it, it should be the first call after the load() statements1. That placement is a hint about its role: it is the file header for package-wide policy, not a rule declaration mixed in with the targets below.

load("//tools:defs.bzl", "my_macro")

package(
    default_visibility = ["//friends:__subpackages__"],
)

cc_library(
    name = "util",
    srcs = ["util.cc"],
)

Everything after that still defines ordinary targets. package() just supplies defaults that those targets inherit unless they override them explicitly1,2.

default_visibility

The most important use of package() is setting default_visibility for targets that omit their own visibility attribute2. This uses the same visibility language introduced in 0.2.4 Visibility. When the same client set has to be reused in many places, that is usually a sign to model it as a named allowlist with 0.2.5 package_group instead of copying long visibility lists by hand.

If a rule has no explicit visibility, Bazel falls back to the package default when one exists. If there is no package default either, the rule falls back to private visibility2. An explicit visibility = [...] on the target wins over the package default.

package(
    default_visibility = ["//friends:__subpackages__"],
)

cc_library(
    name = "impl",
    srcs = ["impl.cc"],
)

cc_library(
    name = "api",
    srcs = ["api.cc"],
    visibility = ["//visibility:public"],
)

Here impl inherits the package default, while api opts out and declares its own visibility. Bazel also treats the package itself as part of the effective visibility, so sibling targets in the same package can still see each other2.

This is convenient, but it is also easy to overuse. Setting default_visibility = ["//visibility:public"] makes every target in the package public unless each one opts back out. The official guidance is to avoid that pattern and mark only real public API targets explicitly2. package() is best when most targets in a package genuinely share the same visibility policy.

default_testonly

The second practical default is default_testonly. Setting:

package(default_testonly = True)

marks targets in that package as test-only by default3. This is useful when an entire subtree is meant for experiments, fixtures, or helper code that should not leak into production dependencies3.

The effect is enforcement, not just documentation. If a non-test target depends on a test-only target, Bazel fails during analysis:

ERROR: .../app/BUILD.bazel:3:12: in java_binary rule //app:server:
    non-test target '//app:server' depends on testonly target
    '//testutil:test_helpers' and doesn't have testonly attribute set

Reproduce this error

That makes default_testonly a lightweight package-wide safety rail. Like other defaults, it can still be overridden on individual targets, so it is a default policy rather than an irreversible lock3.

extra

One Modern Caveat

There is one advanced exception worth knowing exists even if you do not need it yet: symbolic macros may not call native.package(), and targets created inside symbolic macros do not inherit the BUILD file's default_visibility the same way ordinary top-level targets do2,4. For normal hand-written BUILD files in Level 0, you can ignore this. It matters later when you start generating targets through reusable macro abstractions.

key takeaway

package() sets defaults for the whole package. Use it when many targets share the same policy, especially for default_visibility, and keep per-target visibility only for exceptions. Treat default_testonly as a focused safety mechanism for packages that should stay out of production dependency paths.

Check your understanding

1.What does the package() function do in a BUILD file?

2.If a target has its own visibility attribute, and the package also has default_visibility, which one wins?

3.How many times can package() appear in a single BUILD file?

Answer all questions to check

Footnotes

  1. BUILD filespackage() applies metadata to the whole package, appears at most once, and belongs right after load() statements 1 2 3

  2. Visibilitydefault_visibility fallback behavior, explicit target override, package self-visibility, public-default caution, and symbolic-macro caveat 1 2 3 4 5 6

  3. Preventing production code depending on experiments — concrete use of package(default_testonly = True), enforcement error, and per-target override 1 2 3

  4. Macros — symbolic macros may not call native.package(), and package defaults do not apply to macro-created targets in the ordinary way