Overview
A release is the set of decisions about when and how a change becomes visible to users, independent of when its code reaches the production environment. The core principle is separating deploy from release: deploying is the mechanical act of shipping code, releasing is the decision to expose a feature. This page explains that separation, the feature flag mechanism that implements it, how it enables trunk-based development, and how to roll out, roll back, and clean up safely. The pipeline that automates deploys themselves is covered on the CI/CD page; this page covers deciding when users see the result.Deploy and release are different events
Deploying code and releasing a feature usually happen at the same moment, but they answer different questions and belong to different owners.Deploy
Reflecting code in the production environment. A mechanical, repeatable step that can be automated and performed many times a day.
Release
Making a feature available to users. A judgment call about timing — coordination with announcements, support readiness, or business milestones.
Feature Flags
A feature flag is a conditional that switches behavior on or off without a code change. The simplest reliable implementation is an environment variable read at one branch point in the code. In the following example, a new label is rendered only while theFEATURE_NEW_LABEL environment variable is 'true'. Enable it locally to work on the feature, and merge with it disabled in the production environment.
FEATURE_NEW_LABEL=true to the environment — and disabling it is removing that line.
The flag turns “the code is in the production environment” and “the feature is visible” into independent facts. That unlocks:
Merge unfinished work
In-progress features merge into the main branch behind a flag, invisible to users, instead of aging in a long-lived branch.
Deploy often, release deliberately
Deploy to the production environment many times a day while choosing when to release each feature.
Instant rollback
If a released feature misbehaves, turn the flag off. Recovery time is minimal.
Test safely in the production environment
Enable a feature in the verification environment or for internal use first, while users in the production environment still see the old behavior.
Environment-variable flags can be implemented with no extra infrastructure, which makes them a good first step. Adopting a flag management library or service is also worth considering.
Trunk-based development
Trunk-based development is the practice of integrating all work into the main branch in small increments, avoiding branches that live for days or weeks. Long-lived branches accumulate merge conflicts, hide integration problems until the end, and produce large pull requests that are hard to review. Feature flags are what make this practical for features that take more than one pull request to build: each increment merges as soon as it passes review, guarded by the flag, and the feature is enabled only when the last piece lands. The result is that several people can build in the same area with conflicts less likely, and every merge is small enough to review properly. In the following diagram, one feature is split into three increments, each merged into the base branch with the flag off, and the release happens by enabling the flag after the last increment lands. This is the same principle as splitting work into small units — see Task Breakdown for how to slice the work and Pull Requests for keeping each merge reviewable.Isolate impact on the production environment with a topic branch flow
Some changes cannot hide behind a flag — a visual overhaul or a framework migration, where the impact on the production environment cannot be hidden. The topic branch flow keeps granularity in that case. It is a three-layer branch structure that places a topic branch between the base branch and the working branches. Review and integration complete on the topic branch, and the base branch receives nothing until release, so small pull requests keep flowing without affecting the production environment. The flow works as follows.- Cut a topic branch from the base branch, then cut working develop branches from the topic branch.
- Review on PRs from a develop branch into the topic branch. This is the stage where granularity is maintained.
- When the work is ready for the production environment, merge a PR from the topic branch into the base branch. The review at this point can be minimal, because the changes were already reviewed in step 2.
- Merge the base branch’s changes into the topic branch at least once a day to keep conflicts to a minimum.
Gradual rollout and rollback
With deploy and release separated, releasing becomes a sequence of controlled steps rather than a single event.1
Deploy with the flag off
The code reaches the production environment disabled. Users see no change; the deploy itself carries near-zero release risk.
2
Enable in the verification environment
Turn the flag on in the verification environment first. Problems surface before any user is exposed — the earlier a defect is found, the cheaper it is to fix.
3
Release in the production environment
Enable the flag in the production environment at the chosen timing. If the rollout can be scoped, start with a specific group of users and widen the audience gradually.
4
Roll back by turning the flag off
If the feature misbehaves, disable the flag.
Test both states, then remove the flag
A flag doubles the states your code can be in, and both states run in the production environment at some point in the feature’s life. Write tests for each side of the branch:Related pages
Task Breakdown
Slice features into increments small enough to merge behind a flag.
Pull Requests
Keep each merge small and reviewable.
Test Code
Tests that protect both flag states and make flag removal safe.