doc/RELEASING.md
This document describes the SurrealDB release workflow, including how to perform releases, the branching strategy, and version management.
The release workflow is designed to handle two types of releases:
The workflow is fully idempotent, meaning you can safely retry any release without errors or duplicate resources.
3.0.0-beta): 3.0.0-nightly3.0.0): 3.1.0-nightlynightly)When to use: Never manually trigger unless testing the nightly pipeline.
Versioned releases come in several flavors:
X.Y.Z-<prerelease>.<patch> (e.g., 3.0.0-beta.1, 3.1.0-alpha.2)X.Y.Z-<prerelease> (patch stripped)
3.0.0-beta.2 → Main becomes 3.0.0-betaX.Y.0 (e.g., 3.0.0, 4.0.0)X.(Y+1).0-alpha
3.0.0 → Main becomes 3.1.0-alphaX.Y.Z (e.g., 3.0.1, 3.0.2)v3.0.0 for release 3.0.1)release-typenightly or versioned)nightlyrelease-version3.0.0-beta.1)git-refmainmain - for pre-releases and new stable releasesv3.0.0) - for patch releasespublishfalselatestfalseupdate-mainfalsemain-version4.0.0-alpha)3.5.0, but set main to 4.0.0-alpha instead of 3.6.0-alphaextra-featuresstorage-tikv,jwks,mlreleases/vX.Y.Z # Created during version bump, deleted after release
chore/bump-main-to-vX.Y.Z # Created for main version PR
backport/<issue>-to-X.Y # Created for backporting individual fixes (one per fix)
# Example: backport/56-to-3.0, backport/57-to-3.0
For patch releases, create a branch from the previous version's tag when needed (e.g. git checkout -b releases/3.0 v3.0.0). Use that branch for backports and as the release git-ref; it can be deleted after the patch release.
For pre-releases and stable X.Y.0 releases:
main branchreleases/vX.Y.Z branch created for version bumpreleases/vX.Y.Z is deletedFor patch releases (X.Y.Z where Z > 0):
main firstgit checkout -b releases/3.0 v3.0.0)backport/56-to-3.0)releases/vX.Y.Z is created for the version bump and deleted after releaseBest Practice: Always land fixes on main first, then backport individually. This ensures:
All bug fixes must land on main first, then be backported to release branches.
This workflow ensures:
Each fix gets its own backport PR (e.g., backport/56-to-3.0).
Benefits:
# 1. Fix lands on main
PR #56: "Fix memory leak in query parser" → merged to main
# 2. Create patch branch from previous release tag (when preparing 3.0.1)
git fetch --tags
git checkout -b releases/3.0 v3.0.0
git push origin releases/3.0
# 3. Create individual backport PR
git checkout releases/3.0
git checkout -b backport/56-to-3.0
git cherry-pick abc123 # commit from main
git push origin backport/56-to-3.0
gh pr create --base releases/3.0 --head backport/56-to-3.0
# 4. Review and merge backport PR
# (CI runs, code review happens)
Backport PR merged → releases/3.0 now has the fix
# 5. Repeat for each fix needed in 3.0.1
# 6. When ready, run release workflow
# Git ref: releases/3.0, Release version: 3.0.1
# After release, temporary branch releases/v3.0.1 is deleted
Important: The surrealism-* crates follow independent versioning and are not updated during SurrealDB releases.
0.1.x (independent)3.0.0-beta (workspace-managed)The release scripts automatically detect and version only packages starting with surrealdb-*:
surrealdb, surrealdb-core, surrealdb-server, surrealdb-types, surrealdb-types-derive, surrealdb-profilingsurrealism, surrealism-runtime, surrealism-types, surrealism-macros, surrealism-demoThis is handled by the release scripts using cargo metadata to dynamically detect package names. If you add a new surrealdb-* crate, it will automatically be included in version bumps.
The version on the main branch reflects the next development target, not the current release:
Timeline:
┌─────────────┬─────────────┬─────────────┬─────────────┐
│ Release │ Main Before │ Release │ Main After │
├─────────────┼─────────────┼─────────────┼─────────────┤
│ 3.0.0-beta.1│ 3.0.0-alpha │ 3.0.0-beta.1│ 3.0.0-beta │
│ 3.0.0-beta.2│ 3.0.0-beta │ 3.0.0-beta.2│ 3.0.0-beta │
│ 3.0.0 │ 3.0.0-beta │ 3.0.0 │ 3.1.0-alpha │
│ 3.0.1 │ 3.1.0-alpha │ 3.0.1 │ 3.1.0-alpha │ (no change)
│ 3.1.0 │ 3.1.0-alpha │ 3.1.0 │ 3.2.0-alpha │
└─────────────┴─────────────┴─────────────┴─────────────┘
The workflow automatically determines the next main version:
Pre-release (contains -): Strip patch number
3.0.0-beta.1 → Main: 3.0.0-beta3.0.0-rc.3 → Main: 3.0.0-rcStable X.Y.0: Bump to next minor alpha
3.0.0 → Main: 3.1.0-alpha3.5.0 → Main: 3.6.0-alphaPatch X.Y.Z (Z > 0): No change to main
3.0.1 → Main: unchanged (3.1.0-alpha)Use main-version input when transitioning to next major version:
Release: 3.5.0
Auto: 3.6.0-alpha
Override: 4.0.0-alpha
Always test with a dry-run first:
versionedmain3.0.0-beta.2falsefalse ← Leave unchecked for dry-runAfter successful dry-run:
Example: Releasing 3.0.0-beta.2
Dry-Run:
Release type: versioned
Git ref: main
Release version: 3.0.0-beta.2
Update main: ✗
Publish: ✗
→ Verify dry-run succeeds
Publish:
Release type: versioned
Git ref: main
Release version: 3.0.0-beta.2
Update main: ✗
Latest: ✗
Publish: ✓
Post-Release:
3.0.0-betaExample: Releasing 3.0.0
Dry-Run:
Release type: versioned
Git ref: main
Release version: 3.0.0
Update main: ✓
Publish: ✗
Publish:
Release type: versioned
Git ref: main
Release version: 3.0.0
Update main: ✓
Latest: ✓ ← Mark as latest
Publish: ✓
Post-Release:
3.1.0-alphaExample: Releasing 3.0.1
Important: All fixes must land on main first, then be backported one fix at a time.
Create patch branch from previous tag (if not already created):
git fetch --tags
git checkout -b releases/3.0 v3.0.0
git push origin releases/3.0
Ensure fixes are merged to main:
# All bug fixes should already be merged to main branch
# Example: Fix #56 has been merged to main as commit abc123
Backport each fix individually (one PR per fix):
# For fix #56
git checkout releases/3.0
git pull origin releases/3.0
# Create a backport branch for this specific fix
git checkout -b backport/56-to-3.0
# Cherry-pick the specific fix from main
git cherry-pick <commit-hash-from-main>
# Push the backport branch
git push origin backport/56-to-3.0
# Create PR targeting releases/3.0
gh pr create --base releases/3.0 --head backport/56-to-3.0 \
--title "Backport #56 to releases/3.0" \
--body "Backports fix #56 from main for 3.0.1 release.
Original PR: #56
Original commit: <commit-hash>"
Repeat step 3 for each fix that needs backporting (e.g., fix #57, #58, etc.)
After all backport PRs are merged, proceed with release
Dry-Run:
Release type: versioned
Git ref: releases/3.0 ← Branch created from tag v3.0.0
Release version: 3.0.1
Update main: ✗ ← Don't update main for patches
Publish: ✗
Publish:
Release type: versioned
Git ref: releases/3.0
Release version: 3.0.1
Update main: ✗
Latest: ✓ ← If this is now the latest stable
Publish: ✓
Post-Release:
3.1.0-alphareleases/v3.0.1 is deleted after releaseExample: Releasing 3.5.0 but moving to 4.0.0-alpha on main
Dry-Run:
Release type: versioned
Git ref: main
Release version: 3.5.0
Update main: ✓
Main version: 4.0.0-alpha ← Override
Publish: ✗
Publish:
Release type: versioned
Git ref: main
Release version: 3.5.0
Update main: ✓
Main version: 4.0.0-alpha
Latest: ✓
Publish: ✓
Post-Release:
4.0.0-alpha# Initial state: main = 3.0.0-alpha
# Release beta.1
→ Release 3.0.0-beta.1 (from main, update main)
→ Main becomes: 3.0.0-beta
# Release beta.2
→ Release 3.0.0-beta.2 (from main, update main)
→ Main stays: 3.0.0-beta (idempotent)
# Release stable
→ Release 3.0.0 (from main, update main)
→ Main becomes: 3.1.0-alpha
→ Temporary branch releases/v3.0.0 is deleted after release
# Initial state: main = 3.1.0-alpha, v3.0.0 tag exists
# Create patch branch from tag (when preparing 3.0.1)
git checkout -b releases/3.0 v3.0.0
git push origin releases/3.0
# Fix #56 lands on main first
→ PR #56 merged to main
# Backport fix #56 individually
git checkout releases/3.0
git checkout -b backport/56-to-3.0
git cherry-pick <commit-from-main>
git push origin backport/56-to-3.0
# Create PR against releases/3.0, review, and merge
# Fix #57 lands on main
→ PR #57 merged to main
# Backport fix #57 individually
git checkout releases/3.0
git checkout -b backport/57-to-3.0
git cherry-pick <commit-from-main>
# Create PR, review, merge
# After all needed backports are merged
→ Release 3.0.1 (from releases/3.0, no main update)
→ Main stays: 3.1.0-alpha (already has fixes)
# More fixes for 3.0.2 (same branch releases/3.0, or create new from v3.0.1)
→ Fix #60 lands on main
→ Backport #60 to releases/3.0 (one PR)
→ Fix #61 lands on main
→ Backport #61 to releases/3.0 (one PR)
→ Release 3.0.2 (from releases/3.0, no main update)
→ Main stays: 3.1.0-alpha
# Main: 3.1.0-alpha
# Create branches from tags when needed: releases/3.0 from v3.0.0, releases/2.1 from v2.1.4
# Can release patches for older versions simultaneously:
→ Release 2.1.5 (from releases/2.1, branch created from v2.1.4)
→ Release 3.0.2 (from releases/3.0, branch created from v3.0.0)
→ Release 3.1.0-beta.1 (from main)
# All independent, no conflicts
Problem: Branch already exists from previous run
Solution: The workflow is idempotent and automatically deletes/recreates branches. If manual intervention is needed:
# Delete the temporary release branch
git push origin --delete releases/vX.Y.Z
# Re-run the workflow
Problem: Some crates already published
Solution: The workflow automatically detects this and succeeds if all crates are published. If genuinely failed:
cargo publish -p <crate-name>Problem: PR to update main already exists
Solution: The workflow automatically updates existing PRs. No action needed.
Problem: Main version wasn't updated correctly
Solution:
Manually create a PR to fix the version:
git checkout main
git pull
# Build list of surrealdb-* packages (auto-excludes surrealism-*)
PACKAGES=$(cargo metadata --format-version 1 --no-deps | \
jq -r '.packages[].name' | \
grep '^surrealdb' | \
sed 's/^/--package /' | \
tr '\n' ' ')
# Update only surrealdb packages
cargo set-version $PACKAGES X.Y.Z-correct
cargo update -p surrealdb -p surrealdb-core -p surrealdb-server
git commit -am "chore: fix version to X.Y.Z-correct"
git push origin HEAD:chore/fix-version
# Create PR and merge
Note: The release scripts automatically exclude surrealism-* packages by only versioning packages with the surrealdb-* prefix.
Problem: Release failed partway through
Solution: Just re-run the workflow with the same inputs. The workflow is fully idempotent and will:
validate-inputs
↓
bump-version (versioned only)
↓
prepare-vars ←────────────────┐
↓ │
├─→ build (Linux/macOS/Windows)
├─→ publish-crates │
│ ↓ │
├─→ publish (binaries) │
│ ↓ │
├─→ docker │
├─→ package-macos │
│ ↓ │
└─→ propagate ────────────┘
↓
update-main (if update-main=true)
cleanup-release-branch
All multi-line bash logic is extracted to .github/scripts/:
bump-version.sh: Creates temporary release branch (releases/vX.Y.Z) and bumps versionupdate-main-version.sh: Updates main branch version and creates PRcompute-nightly-version.sh: Computes nightly version from main branch