Bazel Book

filegroup Rule

recommended

filegroup() is the built-in rule for saying "these files belong together." It takes an explicit file list, or the result of 0.3.4 Globs, and gives that collection a target label other rules can depend on.1,2 That is the whole move: glob() answers which files match, while filegroup turns the answer into a reusable name in the package.

filegroup(
    name = "config_files",
    srcs = glob(["configs/*.yaml"]),
)

The config_files example above is the common pattern.1,2 The wildcard stays local to this package, but consumers only need the label :config_files. The texts target in glob-retraction follows the same idea: the file selection lives inside the filegroup, and downstream rules can depend on the named target instead of repeating the wildcard.

Why Name The Set?

Raw file lists are fine when only one target uses them. A filegroup becomes useful when the same collection needs to travel to multiple places, especially through data from 0.3.3 Attributes & Semantic Roles.1 The official dependencies docs explicitly recommend enumerating multi-file runtime inputs and then wrapping them in filegroup() so a test or binary can depend on one label instead of a directory label.1

That matters because directory labels are a convenience with real trade-offs. Bazel can track explicit files and glob() matches, but a bare directory in data hides the actual members of the input set and can miss edits to individual files for rebuild purposes.1 A filegroup keeps the dependency explicit without forcing every consumer to repeat the same list.

filegroup vs exports_files()

filegroup and 0.2.7 exports_files() solve different problems. exports_files() makes specific source files in the current package visible to other packages.3,4 If you omit its visibility, those exported files become visible to every package.3

Use exports_files() when another package truly needs a raw file label such as //pkg:schema.sql.4 Use filegroup() when the package API is a collection: configs, fixtures, templates, or some other set that should move through the graph as one named target.1,2 In practice, exports_files() exposes files one by one; filegroup() gives the collection its own stable label.

A Small Rule With Downstream Effects

Because filegroup is a rule, other targets can refer to it with a normal label instead of repeating the underlying file list.1,2 That is why it often appears in data for runtime files now and shows up again when 1.1.2 bazel run & Runfiles introduces runfiles later. The rule itself is simple. The payoff is organizational: the BUILD file starts naming meaningful file sets instead of scattering the same wildcard or file list across multiple consumers.

key takeaway

Reach for filegroup() when a file list stops being a one-off implementation detail and becomes a reusable part of the package interface. glob() chooses the files. filegroup gives that set a label. exports_files() is the different tool for exposing individual raw files directly.

Check your understanding

1.What does filegroup() do?

2.When should you use filegroup() instead of exports_files()?

Answer all questions to check

Footnotes

  1. Dependencies — warns against directory labels for multi-file runtime inputs, recommends explicit enumeration or glob(), and shows filegroup() as the reusable wrapper 1 2 3 4 5 6 7

  2. Sponsored Session: Bazel Management for Developer Productivity Experts - Instructor: Billy Autrey — identifies filegroup as a built-in rule and shows the canonical config_files = glob(["configs/*.yaml"]) pattern 1 2 3 4

  3. BUILD filesexports_files() exports files from the current package and makes them public if visibility is omitted 1 2

  4. Bazel Training 101 (Part 9): Packages, Rules, Targets, and Labels — source files are owned by their package and need exports_files() for cross-package visibility 1 2