Recent from talks
Nothing was collected or created yet.
Bazel (software)
View on WikipediaThis article needs additional citations for verification. (February 2024) |
| Bazel | |
|---|---|
| Developer | |
| Initial release | March 2015 |
| Stable release | 8.4.2[1] |
| Repository | |
| Written in | Java[2] |
| Operating system | Cross-platform |
| License | Apache License 2.0 |
| Website | bazel |
Bazel (/ˈbeɪzəl/[3]) is a free and open-source software tool used for the automation of building and testing software.[2]
Similar to build tools like Make, Apache Ant, and Apache Maven,[2][4] Bazel builds software applications from source code using rules. Rules and macros are created in the Starlark language,[5] a dialect of Python.[4] There are built-in rules for building software written in Java, Kotlin, Scala, C, C++, Go, Python, Rust, JavaScript, Objective-C, and bash scripts.[4][6] Bazel can produce software application packages suitable for deployment for the Android and iOS operating systems.[7]
History
[edit]In 2006,[8] Google started the development of a build tool called Blaze.[9] The motivation was to have a build system that provides both speed and correctness in a large monorepo.[10]
Bazel was created as an open-source port of Blaze, using its anagram as a name.[4] Bazel was first released in March 2015 and entered beta by September 2015.[6] Version 1.0 was released in October 2019.[11]
Rationale
[edit]Bazel has been described as "one of the first openly available cloud build systems". It is able to save the history of previously run commands and share the results across multiple users.[12] To do so, Bazel requires that the inputs and outputs of build targets are fully specified.
Starlark language
[edit]Bazel is extensible with the Starlark programming language.[13] Starlark is an embedded language whose syntax is a subset of the Python syntax. However, it doesn't implement many of Python's language features, such as the ability to access the file I/O, in order to avoid extensions that could create side-effects or create build outputs not known to the build system itself. Such side-effects could potentially lead to incorrect analysis of the build dependency graph.
Languages
[edit]Bazel was designed as a multilanguage build system. It is able to build software combining multiple programming languages within the same repository.
Many commonly used build systems are designed with a preference for a specific programming language. Examples of such systems include Ant and Maven for Java, Leiningen for Clojure, sbt for Scala, etc. In a repository with multiple languages, combining separate build systems and achieving the build speed and correctness benefits described above can be difficult and problematic.
Relation to other build tools
[edit]Build systems most similar to Bazel are Pants,[14] Buck,[15] Please,[16] and the Brazil build system used internally at Amazon.[17] Pants and Buck both aim for similar technical design objectives as Bazel, with Pants being inspired by the Blaze build system used internally at Google.
Bazel, Pants, Buck, and Please adopted Starlark as a BUILD file parser, respective to its BUILD file syntax. Independently developed build systems with similar uses in efficient dependency graph analysis and automated build artifact tracking have been implemented in build systems such as tup.[18]
Sandbox
[edit]Bazel uses a sandbox for compilation steps. When Bazel performs a separate compilation, it creates a new directory and fills it with symlinks to the explicit input dependencies for the rule. For languages like C or C++, this requires the user to be explicit about the dependencies and it prevents the unexpected inclusion of a similarly named header file from another including directory.
This sandbox approach leads to issues with common build tools, resulting in a number of workarounds required to correctly compile code under different architectures. For example, when performing separate compilation for Mac/Darwin architectures, the compiler writes the input paths into SO and OSO symbols in the Mach-O binary, which can be seen with a command like nm -a mybinary | grep SO. These paths are needed for finding symbols during debugging. As a result, builds in Bazel must correct the compiled objects after the fact, trying to correct path-related issues that arose from the sandbox construction using flags like -fdebug-prefix-map and -oso_prefix, the latter having become available in Xcode 11.0. Similar handling needs to take place in linking phases, rewriting the rpath values in shared object libraries with a command like install_name_tool.[19]
Logo
[edit]
Since Bazel's initial release the logo was a green letter "b" stylized into a stem of a basil plant with two leaves. On July 5, 2017, the Bazel Blog announced a new logo,[20] consisting of three green building blocks arranged to shape a heart.
Adoption
[edit]Bazel is commonly used by companies.[21] A few notable users include Google, SpaceX,[22] Stripe,[23] Tinder,[24] and Uber.[25]
See also
[edit]References
[edit]- ^ "Release 8.4.2". 1 October 2025. Retrieved 13 October 2025.
- ^ a b c Yegulalp, Serdar (Sep 11, 2015). "Google open-sources language-agnostic, scalable software tool". InfoWorld. Archived from the original on 25 October 2017. Retrieved 25 June 2016.
- ^ "FAQ - Bazel". bazel.build. Archived from the original on 2016-11-06.
- ^ a b c d Bolton, David (27 April 2015). "Bazel, Google's Open Source Build System - The New Stack". thenewstack.io. The New Stack. Archived from the original on 24 October 2017. Retrieved 25 June 2016.
- ^ "Starlark - Bazel". blog.bazel.build. Retrieved 2018-10-18.
- ^ a b Daws, Ryan (10 September 2015). "Google's software build tool Bazel heads into beta". www.developer-tech.com. Developer Tech. Archived from the original on 23 October 2017. Retrieved 25 June 2016.
- ^ "FAQ - Bazel". bazel.build. Retrieved 25 June 2016.
- ^ Vermeulen, Steve (21 November 2023). "Bazel, From Blaze to Buck2 — A Brief History of Modern Monorepo Build Systems".
- ^ Beyer, Betsy; Jones, Chris; Petoff, Jennifer; Murphy, Niall Richard (23 March 2016). Site Reliability Engineering: How Google Runs Production Systems. "O'Reilly Media, Inc.". p. 90. ISBN 9781491951187. Retrieved 25 June 2016.
- ^ Winters, Titus; Manshreck, Tom; Wright, Hyrum. Software Engineering at Google. O'Reilly. p. 372.
- ^ "Bazel 1.0". blog.bazel.build. Retrieved 2023-10-29.
- ^ Mokhov, Andrey and Mitchell, Neil and Peyton Jones, Simon (2018). "Build Systems à la Carte". Proceedings of the ACM on Programming Languages. 2 (ICFP): 1–29. doi:10.1145/3236774.
{{cite journal}}: CS1 maint: multiple names: authors list (link) - ^ "Starlark Language". bazel.build.
- ^ "Pants: A fast, scalable build system".
- ^ "Buck: A high-performance build tool".
- ^ Please FAQ
- ^ Amazon's Build System
- ^ Shal, Mike (2009). "Build System Rules and Algorithms" (PDF).
- ^ "tools/cpp/osx_cc_wrapper.sh". Github. 5 February 2022.
- ^ Giannini, Steren (5 July 2017). "A new logo and homepage for Bazel".
- ^ "Who's Using Bazel".
- ^ "Building Real-time Systems with Bazel w/ SpaceX". 11 December 2017 – via YouTube.
- ^ "Fast builds, secure builds. Choose two". 4 May 2022.
- ^ Tinder (13 June 2022). "Bazel Hermetic Toolchain and Tooling Migration". Medium.
- ^ "Building Uber's Go Monorepo with Bazel | Uber Blog".
External links
[edit]Bazel (software)
View on GrokipediaIntroduction
Overview
Bazel is an open-source build and test automation tool developed by Google, designed for managing multi-language and multi-platform software projects.[1] It enables developers to automate the compilation, testing, and packaging of codebases ranging from small applications to massive monorepos, emphasizing efficiency across diverse environments.[1] At its core, Bazel automates builds, tests, and related tasks with a focus on speed, scalability, and reproducibility, ensuring consistent outcomes regardless of the project's complexity or the developer's setup.[1] The tool's basic workflow involves declarative BUILD files that define build targets, dependencies, and rules in a platform-agnostic manner; these are then executed through a command-line interface, such asbazel build //path:target for compiling a specific target or bazel test //path:target for running tests.[1] This approach allows for precise control over the build graph, minimizing unnecessary work by analyzing changes and dependencies incrementally.[1]
As of November 2025, the latest stable version is 7.7.1, released on November 12, 2025, with a roadmap targeting Bazel 9.0 as the next long-term support (LTS) release in late 2025.[4][6] Bazel's high-level benefits include fast incremental builds that only re-execute affected components, hermetic execution for isolated and reproducible environments, and support for distributed caching to share build artifacts across teams or machines, thereby accelerating development cycles in large-scale projects.[1]
Key Principles
Bazel's principle of hermeticity ensures that builds are isolated and deterministic, relying solely on explicitly declared inputs to produce identical outputs regardless of the execution environment. This isolation is achieved by sandboxing build actions, preventing access to undeclared system resources or external dependencies, which minimizes variability from host machine differences such as installed tools or network states.[7] As a result, hermetic builds enable reliable reproducibility, allowing the same codebase to yield consistent artifacts across local machines, CI systems, or remote execution environments.[8] The declarative configuration of Bazel uses BUILD files written in Starlark to specify targets and dependencies without incorporating procedural scripts, fostering clarity and ease of maintenance. These files consist primarily of rule declarations, such ascc_library or java_binary, that define what needs to be built rather than the step-by-step processes, which avoids hidden side effects and promotes a data-driven approach.[9] This design enhances readability by encouraging simple, ordered declarations with extensive commenting, while supporting team collaboration through a consistent, non-imperative structure that separates build logic from implementation details.[10]
At the core of Bazel's efficiency is its action graph model, which constructs a directed acyclic graph representing dependencies among build actions like compilation or linking, thereby identifying and skipping unchanged portions to minimize redundant work. During the analysis phase, Bazel generates this graph from the target specifications in BUILD files, enabling incremental builds that only re-execute affected actions based on input changes tracked via content hashes.[11] This model supports safe caching of prior results, further optimizing performance without risking incorrect outputs.[12]
Bazel incorporates multi-platform support natively through its platforms declaration system, allowing builds to target diverse operating systems and architectures—such as Windows, macOS, Linux, or even mobile platforms—from a unified codebase. Platforms are defined using constraint settings and values (e.g., for CPU type or OS version), which Bazel uses to select appropriate toolchains and filter incompatible targets via attributes like target_compatible_with.[13] This enables cross-compilation scenarios, where the host and target platforms differ, ensuring portability without project-specific modifications.[8]
To accelerate feedback in large-scale development, Bazel employs test sharding and parallelism, automatically distributing test execution across multiple processes or machines for concurrent running. Test sharding splits individual tests into parallel shards using flags like --test_sharding_strategy and shard_count, while broader parallelism leverages the action graph to execute independent tests simultaneously on local cores or remote agents.[14] This approach scales efficiently for monorepos with thousands of tests, reducing total runtime and enabling faster iteration cycles.[12]
History
Origins at Google
Bazel originated as an internal build tool at Google known as Blaze, developed starting in the mid-2000s to manage the company's rapidly expanding codebase. By 2006, Google had begun work on Blaze as a response to the limitations of traditional build systems like GNU Make, which struggled with the scale of Google's monorepo containing billions of lines of code.[15] The primary motivations were to enable fast incremental builds and clean builds from scratch, ensuring engineers could efficiently handle a codebase that supported diverse projects across the organization.[16] Initially focused on C++ and Java, Blaze addressed the need for a unified system in a monorepo environment where changes could affect millions of files, replacing massive, error-prone Makefiles that had become unmaintainable as the repository grew.[15] Key internal challenges that drove Blaze's creation included slow build times and reproducibility issues arising from distributed teams working on shared code. Early systems like Make often led to inconsistent results due to varying local environments and undeclared dependencies, exacerbating delays in a codebase exceeding 2 billion lines by the late 2000s.[15] Blaze tackled these by introducing an artifact-centric model with strict transitive dependencies, allowing for hermetic and parallelizable builds that supported millions of daily invocations across Google's infrastructure.[15] This shift enabled faster feedback loops, reducing build times from hours to minutes for large-scale changes and improving collaboration in a monorepo where all engineers shared a single repository.[17] Through 2014, Blaze evolved iteratively to incorporate multi-language support, starting with core languages like C++ and Java before expanding to others such as Python and Go, while deeply integrating with Google's distributed computing infrastructure.[15] Enhancements included distributed execution capabilities by 2008 and stricter dependency enforcement by 2014, which further boosted scalability and reliability for handling incremental changes in a repository that continued to balloon in size.[15] These iterations addressed ongoing challenges like versioning conflicts and language-specific barriers, securing adoption by thousands of internal users and preparing the tool for broader applicability.[16] By 2015, as part of preparations to share the technology externally, Google conducted code audits and stabilized features, reimplementing key aspects into the open-source Bazel project, which was released in March of that year.[15][16]Open-Sourcing and Evolution
Bazel was publicly announced on March 24, 2015, and released as an open-source project on GitHub, serving as a port of Google's proprietary Blaze build system while omitting internal components to comply with licensing restrictions.[16] The initial release, version 0.1.0, followed later that year on September 8, 2015, introducing core functionality for multi-language builds under the Apache License 2.0. Key milestones marked Bazel's maturation, including the release of version 1.0 in October 2019, which established stable APIs and signaled production readiness after years of iterative development.[18] Bazel 5.0, released in January 2022, introduced experimental support for Bzlmod, a modern dependency management system designed to simplify external repository handling and replace legacy WORKSPACE files.[19] This version also enhanced Windows compatibility, enabling more robust cross-platform builds without requiring Bash for most rules. Bazel 7.0 LTS, launched in December 2023, further improved configurability by enabling Bzlmod, Build Without the Bytes (BwoB), and Skymeld caching as defaults, alongside platform-based toolchain resolution for greater flexibility.[20] Bazel 8.0 LTS, released in December 2024, made Bzlmod the default dependency system, advanced Starlarkification of native rules, and introduced symbolic macros for improved build ergonomics.[21] The open-source community's growth accelerated with the inaugural BazelCon conference in 2018, an annual event fostering collaboration among users, maintainers, and contributors through talks, workshops, and hackathons.[22] Non-Google entities, such as Aspect Build, have played a pivotal role by developing and maintaining open-source extensions like rules_js and rules_py, which extend Bazel's capabilities for JavaScript and Python ecosystems.[23] In 2025, Bazel 7.7.0 was released on October 30 and Bazel 7.7.1 on November 12, primarily addressing bug fixes and stability improvements while maintaining backward compatibility with the 7.0 LTS baseline. The project's roadmap outlines Bazel 9.0 LTS for late 2025, prioritizing a complete transition to Bzlmod as the sole dependency system—deprecating WORKSPACE—and enhancements to Starlark for more expressive rule definitions.[6]Design and Features
Build Execution Model
Bazel's build execution model operates through three distinct phases—loading, analysis, and execution—which collectively process the build from dependency declaration to artifact generation. This phased approach ensures that builds are incremental, deterministic, and scalable by constructing graphs of dependencies and actions while minimizing redundant work.[24] In the loading phase, Bazel parses and evaluates all relevant BUILD files and Starlark extensions (.bzl files) to construct a target graph representing the dependencies among build targets. This phase resolves load() statements in a dependency-ordered manner, instantiating rules and expanding macros to populate the graph without executing any build actions; only the necessary files are read and cached to support incrementality. The target graph captures the structure defined by Starlark rules, which encapsulate custom build logic.[25][26] The analysis phase builds upon the target graph by executing the implementation functions of rules to generate an action graph, a directed acyclic graph (DAG) that specifies the precise commands needed to produce outputs from inputs. Bazel prunes unchanged portions of the graph using fingerprints—hashes derived from inputs, configurations, and prior results—to avoid reanalysis of unmodified targets, enabling efficient incremental builds. This phase validates configurations and resolves platform-specific details but does not run any external tools.[26][24] During the execution phase, Bazel traverses the action graph in topological order, invoking actions (such as compiler invocations) only when their outputs are required and dependencies are satisfied. Actions are parallelized across available resources, controlled by flags like --jobs, to maximize throughput while respecting the DAG's dependencies; sandboxing isolates executions for reproducibility, and caching mechanisms retrieve prior results when fingerprints match. The phase fails if an action encounters missing inputs or command errors.[24][27][25] Bazel supports several target types central to the execution model. Rules are the primary building blocks, defined in Starlark to generate actions during analysis and encapsulate complex behaviors like compiling code or packaging artifacts. Macros serve as higher-level abstractions, functioning as rule generators that expand during loading to reduce boilerplate in BUILD files; for instance, a macro might instantiate multiple related rules for a library setup. Filegroups aggregate inputs from multiple sources into a single target, facilitating dependency management by grouping files or outputs for use in other rules without defining new actions.[28][24][29] To inspect and debug the graphs formed during builds, Bazel provides query tools that operate at different phases. The bazel query command analyzes the post-loading target graph, allowing users to trace dependencies; for example,bazel query 'deps(//path/to:target)' lists all transitive dependencies required to build the specified target. Complementary tools include cquery, which queries the configured target graph after analysis to account for build flags and select() expressions, and aquery, which examines the action graph to reveal executed commands. These tools support functions like rdeps (reverse dependencies) and somepath (shortest paths) for detailed diagnostics.[30][31][11]
Error handling in the execution model emphasizes detailed diagnostics to aid resolution. In the loading and analysis phases, Bazel reports configuration issues, such as invalid Starlark syntax or unresolved dependencies, with precise error messages indicating the offending BUILD file or rule. During execution, missing dependencies trigger failures with traces of the dependency chain; flags like --verbose_failures display full command lines for failed actions, while --strict_java_deps (or equivalents for other languages) enforces checks, escalating undeclared dependencies from warnings to errors. Options like --explain and --subcommands provide logs and command previews to facilitate troubleshooting without full builds.[27][29]
Sandboxing and Reproducibility
Bazel employs sandboxing to isolate build actions, ensuring that each action executes in a restricted environment where only explicitly declared inputs are accessible. This mechanism prevents undeclared dependencies and side effects, promoting hermetic builds that behave consistently across different machines and invocations. By default, Bazel uses sandboxing on supported platforms to mimic the isolation provided in remote execution environments, thereby avoiding issues like incorrect incremental builds or cache invalidation due to hidden system interactions.[32] The implementation of sandboxing in Bazel leverages operating system-specific features to enforce isolation. On Linux, it utilizes container-like namespaces for process isolation, creating a read-only filesystem view and optionally blocking network access. Inputs are provided via symlinks within anexecroot/ directory, which serves as the action's working directory, while outputs are moved out after execution to prevent interference. On macOS, the sandbox-exec tool restricts file and network access, and a fallback processwrapper-sandbox strategy uses symlinks and post-execution cleanup for broader compatibility. These approaches ensure that actions cannot read or write outside the designated sandbox, minimizing environmental pollution.[32]
Reproducibility in Bazel is bolstered by sandboxing's guarantees, which eliminate non-deterministic factors such as network interactions. Actions run without network access where supported, and build actions are required to produce bit-identical outputs for the same inputs by avoiding non-deterministic elements such as timestamps. Input dependencies are hashed to detect changes precisely, ensuring that rebuilds yield identical results when inputs match, particularly for languages like Java and C++ with stable toolchains. This hermeticity extends to remote execution, where the same isolation model applies without local system variations.[32][33]
Configuration options allow fine-tuning sandbox behavior for debugging and compatibility. The --sandbox_debug flag preserves the sandbox directory after execution, enabling inspection of the exact environment and command invocation. Users can opt out of sandboxing via --strategy=local for legacy tools or performance-critical cases, though this reduces isolation guarantees. Additional flags like --worker_sandboxing enable sandboxing for persistent workers, balancing efficiency with reproducibility.[32]
In continuous integration and continuous deployment (CI/CD) pipelines, sandboxing facilitates reliable remote execution by preventing environment-specific pollution, allowing builds to run identically on local machines or cloud clusters. This reduces maintenance overhead for execution environments and enhances scalability for large-scale projects.[32]
Despite these strengths, sandboxing introduces limitations, including performance overhead—typically a few percent slower on Linux due to setup and teardown costs, which can impact I/O-bound actions more severely. The --reuse_sandbox_directories flag mitigates this by recycling directories, but persistent workers may offer weaker isolation. Platform support varies, with stronger guarantees on Linux and macOS but limited or absent sandboxing on Windows, relying instead on basic process isolation.[32]
Caching and Scalability
Bazel employs action caching as a core mechanism to enhance build efficiency by computing a unique hash for each action based on its inputs, command, and environment, allowing reuse of previously computed outputs without re-execution if the hash matches.[34] This approach ensures that only changed dependencies trigger recomputation, significantly reducing redundant work in incremental builds.[27] The local cache in Bazel stores build artifacts on disk within the output base directory, typically under paths likebazel-out, enabling fast retrieval for subsequent builds on the same machine.[27] Users can configure an additional disk-based cache via the --disk_cache flag, specifying a custom path to persist artifacts across sessions or machines, which helps manage storage for large projects.[34]
For team-wide efficiency, Bazel supports remote caching through integration with services such as BuildBuddy or Google's Remote Build Execution (RBE), where build outputs are uploaded to and retrieved from a shared remote store using protocols like HTTP/1.1 or gRPC.[34] This is enabled by flags like --remote_cache=http://example.com/cache, allowing multiple developers or CI systems to benefit from cached results, provided actions are hermetic and reproducible.[34]
Bazel's scalability for large monorepos, which may contain millions of files, is bolstered by features like persistent worker processes that maintain long-running instances of tools to amortize startup costs and enable cross-action caching, as well as distributed execution via remote execution systems.[1][35] These capabilities allow handling massive codebases by parallelizing actions across multiple machines.[36]
Reported metrics highlight substantial performance gains; for instance, users have achieved up to 10x faster build speeds after adopting Bazel, particularly in environments leveraging remote caching and execution.[3]
Advanced optimizations include disk usage management through configurable cache paths and automatic trimming in the local output tree, while cache invalidation relies on content-addressable hashes to precisely detect input changes without manual rules.[34][27]
Build Language
Starlark Syntax and Semantics
Starlark is Bazel's configuration language, designed as a subset of Python 3 to enable safe and deterministic evaluation during builds, prohibiting side effects such as unrestricted imports, global state modifications, or access to external systems like the file system or network.[37][38] This hermetic approach ensures that the same Starlark code always produces identical results, supporting parallel execution and scalability in large build environments.[39] The language employs indentation-based syntax similar to Python, facilitating readable code structures for defining variables, control flows, and data collections. Basic elements include lists (e.g.,[1, 2, 3]), dictionaries (e.g., {"key": "value"}), functions defined with def (e.g., def my_rule(name, srcs): native.cc_binary(name = name, srcs = srcs)), and conditionals using if statements.[37][40] These features allow concise expression of build logic without the complexity of full Python, while maintaining familiarity for developers.[37]
Semantically, Starlark emphasizes purity and predictability: functions are pure with no side effects, global variables are immutable to prevent shared state issues, and modules are loaded via the load() function (e.g., load(":my_module.bzl", "helper")) to compose reusable code.[37][40] Undefined behaviors, such as unbounded recursion or modifying collections during iteration, trigger errors to enforce determinism; for instance, recursion is not allowed.[37][41] Dictionary iteration order is also deterministic, ensuring reproducible outcomes across runs.[40]
Starlark features a dynamic type system where values are untyped at runtime but support common Python types like integers (limited to 32-bit signed), strings, booleans, lists, and dictionaries.[37] Experimental type annotations, inspired by Python's PEP 484, can be enabled via the --experimental_starlark_types flag to aid static analysis and catch errors early.[37] In the context of Bazel rules, outputs are propagated through providers, such as DefaultInfo for specifying executable files and runfiles, enabling dependencies to access necessary artifacts.[42]
For development and testing, a standalone starlark REPL is available through implementations like the Go or Rust interpreters, allowing interactive evaluation of code snippets outside Bazel. Within Bazel environments, the help() function provides inline documentation for loaded modules and rules directly in BUILD or .bzl files.[29]
Recent evolutions in Starlark, integrated with Bazel releases, focus on enhanced performance and usability; for example, Bazel 7.0 introduced optimizations to the Starlark interpreter, reducing loading and analysis times in large projects.[43] Ongoing improvements in Bazel 7.x series focus on enhanced performance and usability.[6]
Integration with Bazel Workflows
In Bazel, Starlark serves as the primary language for configuring build workflows through BUILD files, which are collections of Starlark expressions that invoke rules to define targets and their dependencies. These files reside in package directories and use functions likeglob to select source files, followed by calls to rules such as java_library or cc_library to register build targets. For instance, a typical BUILD file might contain:
java_library(
name = "lib",
srcs = glob(["*.java"]),
deps = [":other_lib"],
)
java_library(
name = "lib",
srcs = glob(["*.java"]),
deps = [":other_lib"],
)
.bzl files, which are loaded into BUILD files as needed. A rule is created using the rule() constructor, specifying attributes and an implementation function prefixed with an underscore, such as def _impl(ctx):. This function receives a ctx object providing access to inputs, outputs, and actions, and must return a list of providers—structured data that communicates results to dependent targets, like DefaultInfo for executable files. Native rules, such as genrule or filegroup, are predefined in Bazel and available globally in BUILD files without loading, whereas custom rules require explicit loading from .bzl files to support user-defined behaviors for new tools or languages.[28]
Macros provide reusable abstractions in Bazel workflows by encapsulating common patterns of rule calls in .bzl files, which are then invoked from BUILD files via load statements, such as load("//tools:macro.bzl", "my_macro"). Unlike rules, macros expand fully during the loading phase when BUILD files are parsed, generating inline rule calls without executing actions or returning providers; they are ideal for simplifying repetitive configurations but cannot access the ctx object. This expansion-time behavior ensures macros remain purely declarative, promoting modularity while avoiding runtime complexity.[28]
External dependencies in Bazel workflows are managed through workspace definitions, traditionally via WORKSPACE files written in Starlark to fetch and configure repositories, but increasingly through the MODULE.bazel file introduced as the Bzlmod standard in 2021. Bzlmod uses declarative bazel_dep declarations for direct dependencies, with Bazel automatically resolving transitive ones via a module graph, eliminating much of the manual repository rule boilerplate in WORKSPACE. For example, a MODULE.bazel might include bazel_dep(name = "rules_java", version = "6.1.1") to integrate Java support.[44]
Best practices for integrating Starlark into Bazel workflows emphasize simplicity and determinism to enhance maintainability. Developers should avoid global mutable state in .bzl files, as Starlark execution is single-threaded and stateless per evaluation, opting instead for pure functions; the select() function is recommended for conditional logic across platforms or configurations, such as varying dependencies by build target. Debugging workflows benefits from flags like --sandbox_debug in bazel build commands, which preserve sandbox directories post-execution for inspection of file actions and outputs. Additionally, naming conventions—using snake_case for rules and macros, with private implementations starting with _—and limiting BUILD file abstractions to essential macros help ensure readable, scalable builds.[45]
As of 2025, Bazel's evolution underscores the full migration to Bzlmod, with the Bazel 9.0 release roadmap mandating it as the sole mechanism for external dependencies by removing WORKSPACE support entirely, thereby standardizing and simplifying dependency management across projects.[6]
Supported Languages and Platforms
Core Supported Languages
Bazel provides built-in rules for several core programming languages, enabling developers to define and build projects directly within its workspace without requiring external rule sets for basic functionality. These rules are implemented in Starlark and integrated into Bazel's execution model, supporting compilation, linking, and dependency management tailored to each language's conventions.[46] Java support in Bazel includes comprehensive rules such asjava_library for creating reusable Java libraries and java_binary for producing executable JAR files or standalone binaries. The java_library rule compiles Java sources into class files, handles transitive dependencies, and supports incremental compilation, while java_binary packages the output with a manifest and optional runtime dependencies. Annotation processing is enabled through the plugins attribute in java_library, allowing integration with tools like Lombok or Dagger via java_plugin rules that invoke custom processors during compilation. Additionally, ProGuard integration is facilitated by the proguard attribute in java_binary, which applies obfuscation, optimization, and shrinking to reduce binary size for production deployments. These features ensure hermetic builds and compatibility with multiple Java versions through configurable toolchains.[47][48]
For C/C++, Bazel offers native rules like cc_library to build static or shared libraries from C and C++ sources, including headers and implementation files, and cc_binary to link them into executables. The cc_library rule distinguishes between public headers (hdrs) and private sources (srcs), enabling fine-grained dependency control, while cc_binary supports dynamic or static linking via attributes like linkstatic. Toolchains are configured using cc_toolchain_suite and support compilers such as GCC and Clang, with options for custom flags (copts, linkopts) and cross-compilation targets. Bazel Skylib provides utility functions in Starlark for common C/C++ tasks, such as path manipulation and conditional logic, enhancing rule reusability without external dependencies. This setup promotes reproducible builds by isolating compiler environments.[49][50]
Python rules in Bazel encompass py_library for defining importable modules and packages, which compiles sources into bytecode and manages dependencies, and py_binary for creating executable scripts with entry points. These rules support Python 3 via py_runtime configurations, including virtual environment isolation through attributes like create_init for __init__.py files. Pip integration is handled by the official rules_python repository, which allows declaring external packages in requirements.txt and fetching them hermetically using pip_parse and pip_install rules, ensuring version-locked environments. Virtualenv support is built-in, enabling sandboxed execution and dependency resolution without system Python interference.[51]
Bazel's Go support relies on the rules_go set, featuring go_library for packages and go_binary for applications, with automatic handling of Go modules via go.mod integration. Gazelle, a companion tool, generates BUILD files by scanning Go sources and dependencies, automating the discovery of imports and test files to maintain consistency across large codebases. For Cgo-enabled builds, rules like go_binary configure cross-language linking with C/C++ toolchains, supporting external C libraries while preserving Go's module system. This combination facilitates scalable, reproducible Go workflows.[52][53]
Dedicated rulesets for Android and iOS enable mobile app development within Bazel. For Android, android_library compiles Java/Kotlin sources into AAR or JAR artifacts, integrating with resource processing and manifest merging, while android_binary assembles complete APKs with signing and alignment options. iOS support includes objc_library for Objective-C and Swift code, producing static libraries or frameworks with automatic SDK linking (e.g., UIKit, Foundation), and ios_application for bundling into IPA files, handling code signing and provisioning profiles. These rules leverage Apple's Xcode toolchains for native compilation.[54][55][56]
Bazel's platform support facilitates cross-compilation through the --platforms command-line flag, which specifies target architectures (e.g., --platforms=@platforms//os:android --platforms=@platforms//cpu:arm64) independent of the host machine. Hermetic toolchains, defined via platform and constraint_value rules, encapsulate compilers and libraries to eliminate system dependencies, ensuring builds are portable across Windows, macOS, and Linux. This model supports multi-platform workflows, such as building for ARM from x86 hosts. For languages beyond these core ones, users can extend Bazel with custom rules.[13][57]