At a glance

For every --incompatible_* flag we have a GitHub issue that explains
the change in behavior and provides a migration recipe.

The migration window is at least one release long and is set by the author of the incompatible change.

We announce what set of flags we indend to flip with the next release one release in advance.

APIs and behavior guarded by an --experimental_* flag can change at any time.

Users should never run their production builds with --experimental_* or --incompatible_* flags.

What is stable functionality?

In general, if an API or a behavior is available in Bazel without
--experimental_... flag, we consider it a stable, supported feature.
This includes:

Starlark language and APIs

Rules bundled with Bazel

Bazel APIs such as Remote Execution APIs or Build Event Protocol

Flags and their semantics

Incompatible changes and migration recipes

When we introduce an incompatible change, we try to make it easier for Bazel
users to update their code. We do this by means of migration windows and
migration recipes.

Migration window is one or more release of Bazel during which a migration from
old functionality to new functionality is possible, according to a migration
recipe.

During the migration window, both the old functionality and the new functionality
are available in the Bazel release. For every incompatible change, we provide
a migration recipe that allows updating the user code (BUILD and .bzl files,
as well as any Bazel usage in scripts, usage of Bazel API and so on) in such a
way that it works simultaneously without any flags with old and new
functionality.

In other words, during a migration window for an incompatible change foo:

--incompatible_foo flag is available in Bazel release and defaults to off.

User code can be updated in such a way that it works simultaneously with
that flag being on or off.

After the code is migrated, the users can check whether they migrated
successfully by building with --incompatible_foo=true. However, their
code will continue to work in the same release in default state (where
--incompatible_foo is of), as well after the migration window is over
(at which point the flag will be effectively on).