Historically, it has been tedious to apply transitions to rules we don’t control. You either had to maintain a fork, apply a patch, or wrap the rule — which is particularly annoying because you then have to manually forward the providers of the underlying rule.

Enter Rule Extensions

Bazel 8 introduced rule extensions, which allow you to augment an existing rule — somewhat similar to subclassing in object-oriented languages. Instead of copying or wrapping a rule manually, you can define a new rule that delegates to a parent rule while modifying selected behavior.

A Simple Transition

Let’s first create a transition that forces opt as the compilation mode:

def _opt_transition_impl(_settings, _attr):
    return {"//command_line_option:compilation_mode": "opt"}

opt_transition = transition(
    implementation = _opt_transition_impl,
    inputs = [],
    outputs = ["//command_line_option:compilation_mode"],
)

Nothing fancy — this transition forces the rule it’s applied to to always build in opt, regardless of the --compilation_mode specified on the command line.

Applying the Transition

Here I’m demonstrating this with swift_library, but the concept is the same regardless of the rule:

opt_swift_library = rule(
    implementation = lambda ctx: ctx.super(),
    parent = swift_library,
    cfg = opt_transition,
)

That’s it. The new opt_swift_library behaves exactly like swift_library, except it always builds in opt mode.

For the sake of completeness, here is the entire .bzl file:

load("@rules_swift//swift:swift_library.bzl", "swift_library")

def _opt_transition_impl(_settings, _attr):
    return {"//command_line_option:compilation_mode": "opt"}

opt_transition = transition(
    implementation = _opt_transition_impl,
    inputs = [],
    outputs = ["//command_line_option:compilation_mode"],
)

opt_swift_library = rule(
    implementation = lambda ctx: ctx.super(),
    parent = swift_library,
    cfg = opt_transition,
)

Wrapping Up

There’s much more you can do with rule extensions, but being able to easily apply transitions to third-party rules is already a huge win.

To learn more about what’s possible, check out Keith’s excellent article on this topic.