How to create and publish a Radius release
August 12, 2026 · View on GitHub
Purpose
This document is the maintainers' reference for cutting and publishing a Radius release across the radius-project/radius, radius-project/docs, radius-project/samples, and azure-octo/deployment-engine repositories. It covers release candidates, final releases, and patch releases, and the branching, tagging, and validation steps each requires. It is intended for project maintainers with release responsibility, not day-to-day contributors.
Prerequisites
Before starting a release, ensure you have:
-
Release version number: Determine the version in the form
<major>.<minor>.<patch>(e.g.,0.56.0). -
Repository access: Write access to
radius-project/radius,radius-project/docs,radius-project/samples, andazure-octo/deployment-engine. -
GPG signing configured: The
azure-octoorg requires verified tags. Set up GPG signing locally before starting. -
Local clone of
radius-project/radius: Clone directly from the organization repo, not a personal fork. CI workflows require access to organization secrets that are not available in forks.git clone git@github.com:radius-project/radius.git
Important: For the entire release process, create branches directly in repositories under the
radius-projectorganization. Do not use personal forks.
Terminology
| Term | Description | Example |
|---|---|---|
| RC release | A release candidate for internal validation before public release. Create additional RCs if validation fails. | v0.56.0-rc1, v0.56.0-rc2 |
| Final release | A public release, built from the last validated RC. | v0.56.0 |
| Patch release | A bug-fix release for an existing final release. | v0.56.1 |
| Release channel | A <major>.<minor> pair that groups all releases for a version. | 0.56 |
| Release branch | A branch in the format release/<channel> that holds release code. | release/0.56 |
How releases work
Release channels
Each release belongs to a channel named <major>.<minor>. The rad CLI and control plane for a given channel only interact with assets from that channel. Patch releases within a channel (e.g., v0.56.1) maintain backward compatibility with the original release.
Compatibility: Cross-channel compatibility is not guaranteed. For example, the behavior of a
0.55radCLI talking to a0.56control plane is unspecified.
Cadence
Radius follows a monthly release cadence. All contributions merged to main through the pull-request process are included in the next scheduled release.
Release automation
Two GitHub Actions workflows drive the release process. No one manually creates tags in radius-project repos. Tags for repos in the radius-project organization are created automatically by the release.yaml workflow. (The Deployment Engine repo in the azure-octo organization still requires manual tagging — see the release steps below.)
-
Release Radius (
release.yaml): Triggered wheneverversions.yamlis pushed tomainor arelease/*branch. This workflow:- Scans
versions.yamlin.supported[]order and selects the first.versionentry whose git tag does not already exist - Checks whether a git tag for that version already exists
- Automatically creates and pushes the version tag (e.g.,
v0.56.0-rc1) forradius,recipes,dashboard, andbicep-types-aws - Creates the release branch (
release/<channel>) if it does not already exist - Dispatches Deployment Engine image publishing to GHCR
- Skips tag/branch creation if the release branch already exists and the trigger was a push to
main(this prevents duplicate work whenversions.yamlis merged tomainand later cherry-picked to the release branch)
Note: The workflow always checks out and reads
versions.yamlfrommain, even when triggered by a push to arelease/*branch. This means the version must be merged intomainbefore the cherry-pick to the release branch triggers tag creation.Important:
- Add the new release version at the top of the
supportedlist inversions.yaml. - Change only one version per PR.
- If more than one new untagged version is present in
supported,release.yamlfails rather than guessing which one to release.
- Scans
-
Build and Test (
build.yaml): Triggered byv*tag pushes (created byrelease.yamlabove). This workflow:- Builds CLI binaries and container images
- Dispatches Bicep types publishing
- Creates the GitHub Release (auto-generated notes for RCs, or from
docs/release-notes/for final and patch releases)
The automated flow after merging a versions.yaml change:
Merge versions.yaml change (to main or release/* branch)
→ release.yaml detects new version in versions.yaml
→ release.yaml creates git tag + release branch (if needed)
→ tag push triggers build.yaml
→ build.yaml publishes artifacts + creates GitHub Release
When does tag creation happen?
| Scenario | Trigger | What happens |
|---|---|---|
| First RC | versions.yaml merged to main | release.yaml creates the release branch from main and pushes the RC tag |
| Subsequent RC | versions.yaml cherry-picked to release/* | release.yaml runs on the release branch and pushes the new RC tag |
| Final release | Version bump cherry-picked to release/* | release.yaml runs on the release branch and pushes the final tag |
| Patch release | versions.yaml cherry-picked to release/* | release.yaml runs on the release branch and pushes the patch tag |
Cherry-pick workflow
All release types follow the same pattern: changes merge to main first, then cherry-pick to the release branch (release/<channel>). The release branch is what gets tagged and built.
| Release type | What to cherry-pick to the release branch |
|---|---|
| First RC | Nothing — the release branch is created automatically from main |
| Subsequent RC | versions.yaml update + any additional bug fixes |
| Final release | A single commit with the version bump and release notes |
| Patch release | Bug-fix commits + versions.yaml update + patch release notes |
Always use
git cherry-pick -xto preserve traceability.Key concept: The RC release is built from the release branch (
release/x.y), not directly frommain. After the initial RC is created, the release branch is used for subsequent RCs and for the final release. Changes for RC-2 and all subsequent RCs are first merged tomainand then cherry-picked to the release branch. This applies to theversions.yamlupdate as well as any optional commits (bug fixes, late features) that must be included in the RC.
Creating an RC release
When starting the release process, first create an RC release. If validation fails, create additional RCs (incrementing the RC number) until validation passes.
Step 1: Start a Teams release thread
Before performing any release actions, start and join a meeting in the team's Microsoft Teams channel dedicated to releases. Title the thread with the target final release version for the entire release cycle (for example, use "Release v0.56.0", not "Release v0.56.0-rc1").
Turn on transcription for the meeting. Recording is not necessary. Verbally announce each step as you perform it, and post updates in the thread with the same information. This creates a detailed timeline of the release process that can be reviewed later for improvements and serves as a record of the release.
Use this same thread throughout the entire release lifecycle, including all RCs and the final release:
- Log every action as you perform it, including which step you are on, what commands you ran, and the result (success or failure).
- Log any issues encountered during the release, including error messages, failed workflows, and the resolution.
- Announce completion of the release in the thread once all steps are finished and validation passes.
This detailed release log helps the team improve future releases by reviewing the overall timeline, identifying inefficiencies, errors, or bottlenecks, and preserving institutional knowledge about the release process.
Step 2: Tag the Deployment Engine
Run the following in a local clone of the Deployment Engine repo, replacing vX.Y.Z-rcN with the RC version (e.g., v0.56.0-rc1):
git checkout main
git pull origin main
git tag vX.Y.Z-rcN
git push origin vX.Y.Z-rcN
Note: This manual tagging step is a temporary workaround. Ideally the Deployment Engine Release Workflow would handle this, but GPG signing is not yet configured there. See azure-octo/deployment-engine#456.
Step 3: Update default resource types in the Radius repo
Ensure the default resource type manifests and generated recipe consumers in the Radius repo use the latest eligible resource-types-contrib releases:
Before syncing Radius, publish a stable release from resource-types-contrib for every consumed namespace or recipe pack that has releasable changes. Use the upstream Release Namespace and Release Recipe Pack workflows; they skip unchanged units. The edge fallback is only a bootstrap exception for a unit that has never had a stable release, not a substitute for publishing one. Confirm any remaining empty tag in deploy/manifest/defaults.yaml corresponds to a unit with no stable release upstream.
git checkout main
git pull origin main
git checkout -b <USERNAME>/update-resource-types
make update-resource-types-and-recipe-packs
The target atomically enforces stable-first selection for every resource type namespace and consumed recipe pack. If a stable unit-scoped SemVer tag exists upstream (Radius.Compute/vX.Y.Z or recipe-pack/azure/vX.Y.Z), it pins that release's immutable commit SHA in deploy/manifest/defaults.yaml and records the tag. A legacy stable repository-wide vX.Y.Z tag is accepted only when the unit has no scoped stable release. A main commit is used as the edge fallback only for a unit that has never published any stable release. Prerelease tags do not qualify as stable and cannot be used as the edge fallback. The target copies the manifests listed under defaultRegistration into deploy/manifest/built-in-providers/; recipe packs are not vendored. Generated Azure/AWS workflows read their immutable recipe-pack and resource Recipe sources from the same defaults.yaml catalog at runtime, so no refs are duplicated in workflow files.
To pin a specific stable release, including a rollback to an older known-good release, pass its unit-scoped tag. For example, run make update-resource-types RESOURCE_TYPES_REF=Radius.Compute/v0.2.0 RESOURCE_TYPES_NAMESPACE=Radius.Compute. To request an update for one namespace using normal stable-first selection, pass RESOURCE_TYPES_NAMESPACE on its own. A full commit SHA is accepted only as the edge candidate for a unit with no stable release.
For a targeted recipe-pack rollback or refresh, use its independent recipe-pack/<pack>/vX.Y.Z release series. The command updates its catalog pin but copies no pack files:
make update-recipe-packs
make update-recipe-packs RECIPE_PACKS_NAME=azure RECIPE_PACKS_REF=recipe-pack/azure/v0.2.0
Review the diff and confirm every non-empty tag is a stable unit-scoped or repository-wide release. An empty tag is valid only when that namespace or recipe pack has no stable release upstream; CI rechecks that exception and verifies each stable tag resolves to the recorded SHA.
If the update fails or the copied manifests fail schema validation at startup during testing, you have two options:
- Fix forward: Correct the manifest in
resource-types-contrib, merge the fix, then re-runmake update-resource-types. - Pin to last known good stable release: Re-run
make update-resource-typeswith that release's unit-scoped tag and namespace, then runmake sync-resource-typesto restore the matching manifests. For a namespace with no stable release, pass the previous edge commit SHA instead.
Open a separate PR targeting main in radius-project/radius with the updated catalog and manifest files. Merge it before proceeding to the versions.yaml update.
Step 4: Update versions.yaml
Create a branch from main in the radius-project/radius repo:
git checkout main
git pull origin main
git checkout -b <USERNAME>/release-X.Y.0-rcN
Edit versions.yaml to add the new RC as a supported version. Move the oldest supported version to the deprecated list if needed (example PR).
supported:
- channel: '0.56'
version: 'v0.56.0-rc1'
- channel: '0.55'
version: 'v0.55.0'
deprecated:
- channel: '0.54'
version: 'v0.54.0'
Step 5: Merge to main
Push the branch and create a PR against main:
git push origin <USERNAME>/release-X.Y.0-rcN
After approval, merge the PR to main.
Step 6: Verify the automated release
After merging, the Release Radius workflow automatically runs because versions.yaml changed on main.
- First RC: The workflow creates the
release/X.Ybranch frommainand pushes thevX.Y.Z-rcNtag. The tag push then triggers the Build and Test workflow. No manual tag creation is needed. Verify the release using the checklist below. - Subsequent RCs: The workflow detects that the release branch already exists and skips tag creation. This is expected — the tag will be created when the cherry-pick lands on the release branch in Step 8. Skip ahead to Step 7 for now and return to verify after completing Step 8.
Monitor and verify:
- The Release Radius workflow completes successfully. For the first RC, confirm it created the
release/X.Ybranch and thevX.Y.Z-rcNtag. - The Build and Test workflow (triggered by the tag push) completes successfully. This workflow also dispatches Bicep types publishing automatically.
- An RC release marked as pre-release appears on GitHub Releases.
Step 7: Publish Bicep recipes
In the radius-project/resource-types-contrib repo, manually run the Publish Bicep Recipes workflow. Enter the RC version number without the v prefix as the release version (e.g., 0.56.0-rc1).
Step 8: Cherry-pick additional changes (subsequent RCs only)
Skip this step for the first RC. The release branch was just created from
mainand already contains all changes.
For subsequent RCs (rc2, rc3, etc.), cherry-pick the versions.yaml update and any bug fixes onto the release branch:
git checkout release/X.Y
git pull origin release/X.Y
git checkout -b <USERNAME>/cherry-pick-rcN-to-release-branch
git cherry-pick -x <VERSIONS_YAML_COMMIT_HASH>
git cherry-pick -x <OPTIONAL_FIX_COMMIT_HASH>
Use
git log --oneline mainto find commit hashes.
Push and create a PR targeting the release branch:
git push origin <USERNAME>/cherry-pick-rcN-to-release-branch
After approval, merge the PR. This triggers the release automation on the release branch, creating the new RC tag. Return to Step 6 to verify the release completed successfully.
Step 9: Run validation workflows
-
In
radius-project/radius, run the Release verification workflow from therelease/X.Ybranch. Enter the RC version number without thevprefix as the version (e.g.,0.56.0-rc1). -
In
radius-project/docs, run the Upmerge docs to edge workflow from the previous release branch (e.g., run fromv0.55when releasingv0.56).This generates a PR. Get approval and merge it before proceeding. The PR excludes branch-specific files (
docs/config.tomlanddocs/layouts/partials/hooks/body-end.html). -
In
radius-project/samples, run the Upmerge samples to edge workflow from the previous release branch.This generates a PR. Get approval and merge it before proceeding. The PR excludes
bicepconfig.json. -
In
radius-project/samples, run the Test Samples workflow from theedgebranch. Enter the RC version number without thevprefix as the version (e.g.,0.56.0-rc1).Run this only after the upmerge PR has been merged to
edge. If tests fail, check logs and existing issues in the samples repo. Flaky tests may pass on re-run. If failures persist, file an issue and raise it with maintainers.
Step 10: Assess results
If all validation workflows pass, proceed to creating the final release.
If validation fails, fix the issues on main, then create a new RC (increment the RC number, e.g., rc2, rc3) by repeating the steps above.
Creating the final release
The final release is built from the last validated RC on the release branch. The only change needed is a single cherry-pick that bumps the version and adds release notes. This ensures the final release contains exactly the same code as the validated RC.
Step 1: Update the Teams release thread
Post an update in the Teams release thread (started during the RC release) indicating that the final release process is beginning. Continue logging every action, result, and issue in this thread throughout the final release steps.
Step 2: Tag the Deployment Engine
Run the following in a local clone of the Deployment Engine repo, replacing vX.Y.Z with the final version (e.g., v0.56.0):
git checkout main
git pull origin main
git tag vX.Y.Z
git push origin vX.Y.Z
Note: Same temporary workaround as for RC releases. See azure-octo/deployment-engine#456.
Step 3: Update versions.yaml and create release notes
Create a branch from main:
git checkout main
git pull origin main
git checkout -b <USERNAME>/final-release-X.Y.0
-
Update
versions.yaml: Change the RC version to the final version (example PR).supported: - channel: '0.56' version: 'v0.56.0' # was v0.56.0-rc1 -
Create a draft release notes file: Add
docs/release-notes/vX.Y.Z.mdusing the release notes template. See the release notes README for instructions (example PR). -
Push and create a PR against
main. The PR will receive an auto-generated release notes comment — use it to fill in the changelog and contributor list in your release notes file. Push an update with the completed release notes.
The PR will be squash-merged into a single commit on
main, which is the commit you will cherry-pick to the release branch.
Step 4: Merge to main
After approval, squash-merge the PR.
Step 5: Cherry-pick to the release branch
Cherry-pick the squash-merged commit (version bump + release notes) onto the release branch.
git checkout release/X.Y
git pull origin release/X.Y
git checkout -b <USERNAME>/final-release-X.Y.0-cherry-pick
git cherry-pick -x <COMMIT_HASH>
Use
git log --oneline mainto find the commit hash.
Push and create a PR targeting the release branch (example PR):
git push origin <USERNAME>/final-release-X.Y.0-cherry-pick
After approval, merge the PR.
Step 6: Verify the automated release
After the cherry-pick PR is merged to the release/X.Y branch, the Release Radius workflow automatically runs because versions.yaml changed on a release/* branch. It reads the final version from versions.yaml, creates and pushes the vX.Y.Z tag, and the tag push triggers the Build and Test workflow. No manual tag creation is needed.
Monitor and verify:
- The Release Radius workflow completes successfully and creates the
vX.Y.Ztag. - The Build and Test workflow (triggered by the tag push) completes successfully. Allow up to ~20 minutes for release assets to be published.
- A final release (not pre-release) appears on GitHub Releases.
Step 7: Publish Bicep recipes
In the radius-project/resource-types-contrib repo, manually run the Publish Bicep Recipes workflow. Enter the final version number without the v prefix as the release version (e.g., 0.56.0).
Step 8: Publish docs and samples
-
In
radius-project/docs, run the Release docs workflow from theedgebranch. Enter the version number without thevprefix (e.g.,0.56.0). -
In
radius-project/samples, run the Release samples workflow from theedgebranch. Enter the version number without thevprefix (e.g.,0.56.0).
Step 9: Run validation workflows
-
In
radius-project/radius, run the Release verification workflow from therelease/X.Ybranch. Enter the final version number without thevprefix as the version (e.g.,0.56.0). -
In
radius-project/samples, run the Test Samples workflow from theedgebranch. Enter the final version number without thevprefix as the version (e.g.,0.56.0).If tests fail, check logs and existing issues in the samples repo. Flaky tests may pass on re-run. If failures persist, file an issue and raise it with maintainers.
If all workflows pass, the release is complete. Post a final update in the Teams release thread announcing the successful release and summarizing the timeline.
Patching
Use this process to fix a bug in an already-released version.
Note: If the patch includes a fix to the Deployment Engine, you must also tag the Deployment Engine with the patch version (e.g.,
vX.Y.Z) before proceeding, following the same process as in the RC and Final release sections.
Step 1: Start a Teams release thread
Start a new thread in the team's Microsoft Teams release channel titled with the patch version (e.g., "Patch Release v0.56.1"). As with RC and final releases, log every action, result, and issue in this thread throughout the patch release process.
Step 2: Merge the fix to main
Open a PR with the bug fix targeting main. After approval, merge it.
Step 3: Update versions.yaml and create patch release notes
Create a branch from main:
git checkout main
git pull origin main
git checkout -b <USERNAME>/patch-X.Y.Z
- Update
versions.yamlto reflect the new patch version (e.g.,v0.56.1). - Create patch release notes at
docs/release-notes/vX.Y.Z.mdusing the patch release notes template.
Push and create a PR against main:
git push origin <USERNAME>/patch-X.Y.Z
After maintainer approval, merge the PR.
Step 4: Cherry-pick to the release branch
Cherry-pick the bug fix, the versions.yaml update, and the patch release notes onto the release branch:
git checkout release/X.Y
git pull origin release/X.Y
git checkout -b <USERNAME>/patch-X.Y.Z-cherry-pick
git cherry-pick -x <BUGFIX_COMMIT_HASH>
git cherry-pick -x <VERSIONS_AND_RELNOTES_COMMIT_HASH>
Use
git log --oneline mainto find commit hashes.
Push and create a PR targeting the release branch:
git push origin <USERNAME>/patch-X.Y.Z-cherry-pick
After approval, merge the PR.
Step 5: Verify the automated release
After the cherry-pick PR is merged to the release/X.Y branch, the Release Radius workflow automatically runs because versions.yaml changed on a release/* branch. It reads the patch version from versions.yaml, creates and pushes the vX.Y.Z tag, and the tag push triggers the Build and Test workflow. No manual tag creation is needed.
Monitor and verify:
- The Release Radius workflow completes successfully and creates the
vX.Y.Ztag. - The Build and Test workflow (triggered by the tag push) completes successfully. Allow up to ~20 minutes for release assets to be published.
- A patch release appears on GitHub Releases.
Step 6: Run validation workflows
-
In
radius-project/radius, run the Release verification workflow from therelease/X.Ybranch. Enter the patch version number without thevprefix as the version (e.g.,0.56.1). -
In
radius-project/samples, run the Test Samples workflow from theedgebranch. Enter the patch version number without thevprefix as the version (e.g.,0.56.1).If tests fail, check logs and existing issues in the samples repo. Flaky tests may pass on re-run. If failures persist, file an issue and raise it with maintainers.
If all workflows pass, the patch release is complete. Post a final update in the Teams release thread announcing the successful patch and summarizing the timeline.