Release Management
Release management coordinates when and how Python services ship: versioning rules, release trains, change approvals, and communication. Good release hygiene makes rollback credible and stakeholders predictable.
Recipe
Quick-reference recipe card - copy-paste ready.
# Release: orders-api v2026.07.09
## Artifacts
- Image: `orders-api:sha-9f2a1bc` (Python 3.14.0)
- Wheel (internal lib): `acme-billing==2.4.0`
## Migrations
- alembic `20260709_add_tax_code` (expand, backward compatible)
## Rollback
- `kubectl rollout undo` to `sha-7c1b2aa`
- Pause `billing` workers if queue depth > 5k
## Stakeholders
- #releases, support macro updatedWhen to reach for this:
- Multiple squads ship the same platform weekly
- Customer-facing API with SLA commitments
- Shared libraries consumed by many internal services
- Compliance requires change records
Working Example
"""version_bump.py - automate service version metadata for release notes."""
from __future__ import annotations
import subprocess
from dataclasses import dataclass
from datetime import date
@dataclass(frozen=True)
class ReleaseMetadata:
service: str
git_sha: str
python: str
release_date: date
def git_short_sha() -> str:
return subprocess.check_output(["git", "rev-parse", "--short", "HEAD"], text=True).strip()
def build_release_notes(meta: ReleaseMetadata, changes: list[str]) -> str:
lines = [
f"# {meta.service} release {meta.release_date.isoformat()}",
f"- Git: `{meta.git_sha}`",
f"- Python: {meta.python}",
"",
"## Changes",
]
lines.extend(f"- {c}" for c in changes)
return "\n".join(lines)
if __name__ == "__main__":
meta = ReleaseMetadata("orders-api", git_short_sha(), "3.14.0", date.today())
print(build_release_notes(meta, ["Add tax code field (nullable)", "Fix Celery retry backoff"]))What this demonstrates:
- Release notes tie customer-visible changes to git SHA
- Migration risk called out explicitly for operators
- Rollback steps live beside forward deploy instructions
- Automation reduces copy-paste errors in
#releasesposts
Deep Dive
How It Works
- Release train - Fixed cadence (e.g., Tue/Thu) with cutoff for merge.
- Semver - Libraries use MAJOR.MINOR.PATCH; breaking changes bump major.
- Change management - CAB review for destructive migrations or cross-service flag days.
- Artifact immutability - Build once, promote through environments.
- Communication - Support macros and status templates updated before prod promote.
Release Types
| Type | Cadence | Typical scope |
|---|---|---|
| Standard train | Weekly | Features behind flags |
| Hotfix | Ad hoc | SEV mitigation |
| Library patch | Daily automerge | Security CVE |
| Major platform | Quarterly | Python minor bump |
Python Notes
# pyproject.toml - library versioning
[project]
name = "acme-billing"
version = "2.4.0"
requires-python = ">=3.13"Gotchas
- Floating
:latestin prod - Rollback ambiguity. Fix: Immutable tags with SHA; record in deploy annotation. - Release notes without migration section - Ops surprised by locks. Fix: Alembic revision IDs mandatory in notes.
- Train without cutoff - Last-minute risky merges. Fix: Code freeze 24h before prod with exception process.
- Different Python in worker vs API - Subtle pickle/schema bugs. Fix: Single base image policy per release.
- Skipping stakeholder notification - Support blindsided. Fix:
#releasespost is a release gate, not optional.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Continuous deploy | Strong flags + canary | Heavy schema coupling |
| GitOps (Argo CD) | K8s fleet | Manual Lambda-only shop |
| Dark launches | ML model swaps | Regulated disclosure required |
| Long-lived branches | Legacy release model | Modern trunk-based team |
FAQs
How often should Python services release?
Daily to weekly with flags is common when migrations are expand-contract and CFR is low.
Do libraries follow the same train?
Libraries release on demand; services pin versions in lockfile per train.
What is a release captain?
Rotating engineer owns checklist, comms, and go/no-go for that train.
How handle hotfix during freeze?
IC or release captain approves; document exception in change ticket.
Should notebooks ship on the train?
No - batch jobs and notebooks have separate promotion with data owner sign-off.
How version internal APIs?
URL or header versioning documented in changelog; consumers pin client SDK.
What about monorepos?
Per-service tags and release notes; one merge can trigger multiple deploy pipelines.
How record changes for audit?
Link JIRA/Linear tickets in release notes; retain build artifacts 90+ days.
When delay a train?
Error budget exhausted, open SEV1, or migration load test failed in staging.
Does uv affect release management?
uv speeds CI; release process still gates on tests, migrations, and canary.
Related
- Rollback Strategies - when trains go wrong
- Environments & Config Promotion - promote path
- DORA Metrics - measure delivery health
- CI/CD Pipelines - automation
- Packaging & Publishing - library releases
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.