Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions docs/contributing/feature-flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,3 +327,75 @@ follows:

Local and development self-hosted installations may choose to configure alternative
[data sources](#flag-data-sources) to more quickly adopt a feature.

## Removing a feature flag

Once the flag has been enabled in all environments and the feature is verified to be functioning as
expected, the final steps are to remove the flagged conditional logic from our codebase, then the
flag itself. When defining the tasks for feature-flagged code, be sure to include a cleanup task for
removing this logic. You may want to consider multiple tasks - one for each of the steps in the
removal process.

Due to the complexity of the different client deployments and how we expose feature flags through
our API, it is important that each feature flag be removed in the appropriate sequence, with the
appropriate timing considerations.

### Step 1: Remove business logic and client references

:::tip Timing

**Step 1** can take place immediately after the feature is released.

:::

In this step, teams should remove all business logic that relies on the flag from both client and
server code. This includes all references in the client codebase, and also any business logic on the
server that checks the flag value.

:exclamation: This does **not** include removing the flag from the FeatureFlagKeys on the server --
we must leave this here for backward compatibility, so that existing clients who have not updated
continue to be served the correct "on" value when querying for the flag, even after the new server
release.

This code should then be deployed to all clients and to the server.

### Step 2: Remove flag from server

:::tip Timing

**Step 2** can take place either:

- Three major releases after the feature flag was removed from the clients in **Step 1**, if the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

โš ๏ธ This was mentioned to me recently (I did not know it was documented this way) and I didn't think was how anyone operated. As I read it this is to protect older clients from regressing when using a newer server, and I don't think we should care about this use case -- why not expect the client from the first phase release to be in place for when the next server release deploys?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need that in order to meet our backward compatibility guarantees? If I release a feature in version N, and then remove the feature flag from clients and server in version N+1, when server version N+1 is deployed, the version N client will no longer receive the feature flag value in the /api/config response and default to false, disabling the feature that we just rolled out.

Is there some protection in place that I'm not aware of that would prevent that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a subtlety to feature flag usage, and I think literally having "feature" in the term can be confusing, but the intention is for them to live and die fast for the purposes of deployment and release resiliency first and foremost; gating functionality is indeed a benefit but it wasn't quite the point when I introduced them.

We do of course have a support policy, but that's for client-server interaction and my stance is that feature flags are not actually related to it. If you're going to use and benefit from something in N, then when N+1 comes you must also stay up to date if you expect to continue using whatever was flagged. Our support policy is about maintaining an operable state and not about getting anything and everything available.

Put simply, I feel the best way to operate is to have a client release that removes the use of the flag, is released and therefore available to users, and then the server can cease emitting that flag.

Copy link
Member

@eliykat eliykat Oct 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not opposed to this change, but I can just about guarantee that most devs have the same understanding as @trmartin4, so please make sure this is widely shared in Slack.

It also means (as I understand it) that we may not necessarily remove old code with the feature flag like we do today. e.g. a feature flag would be removed the N+1 release, but you may have to keep an old endpoint until N+3 if it's a breaking change. Whereas today we would keep both until N+3 and remove them together. That's not a problem, maybe that's even a better way to think about it, but something we'll have to think about differently.

flag is used in non-web clients, or
- At the same time as the feature flag was removed from the clients in **Step 1**, if the flag is
only used on the web client.

:::

Once we have satisfied the backward compatibility
[requirements](https://bitwarden.com/help/bitwarden-software-release-support/) for our clients, we
can completely remove the feature flag from the server codebase. This can be done by removing the
flag value from the `FeatureFlagKeys`.

:::info Determining when it's safe to remove

To assess when a flag was removed from the TypeScript clients, you can check the
[history](https://github.com/bitwarden/clients/commits/main/libs/common/src/enums/feature-flag.enum.ts)
of the `FeatureFlagKeys` enum.

:::

### Step 3: Remove flag from LaunchDarkly

:::tip Timing

**Step 3** can take place immediately after the changes have been deployed the cloud servers for
Step 2. Appropriate time should be taken to ensure a rollback of the release will not be required.

:::

Once the server codebase has been deployed to all environments without any references to the flag,
the flag should be archived in LaunchDarkly.

Feature flags not accessed for a long period of time will automatically move to an "inactive" state
that can also help with identifying technical debt to clean up.