What Is Release Management?
Release management is the process of planning, scheduling, building, testing, and deploying software releases. It bridges the gap between "development done" and "users can use it." A mature release process makes deployments boring (in a good way) — predictable, low-risk, and routine.
Release Cadence Options
| Cadence | Frequency | Best For | Risk Level |
|---|---|---|---|
| Continuous Deployment | Multiple times/day | SaaS, web apps | Lowest (small changes) |
| Continuous Delivery | On-demand (anytime) | Teams with good CI/CD | Low |
| Sprint Release | Every 1-2 weeks | Scrum teams | Medium |
| Monthly Release | Monthly | Enterprise, B2B | Medium-High |
| Quarterly Release | Quarterly | Regulated, desktop apps | High (big bang) |
Semantic Versioning
SemVer: MAJOR.MINOR.PATCH
- MAJOR (X.0.0): Breaking changes — existing users must update their integration. Example: API v1 to v2.
- MINOR (0.X.0): New features that are backward compatible. Example: New API endpoint added.
- PATCH (0.0.X): Bug fixes that are backward compatible. Example: Fixed null pointer exception.
Pre-release: 1.0.0-beta.1 | Build metadata: 1.0.0+20240315
Feature Flags
// Feature Flag Implementation
interface FeatureFlag {
key: string;
name: string;
description: string;
type: 'release' | 'experiment' | 'ops' | 'permission';
status: 'enabled' | 'disabled' | 'percentage' | 'user-segment';
rolloutPercentage?: number;
targetUsers?: string[];
targetSegments?: string[];
createdDate: Date;
owner: string;
expiryDate?: Date; // Feature flags should not live forever
}
// Simple feature flag service
class FeatureFlagService {
private flags: Map = new Map();
isEnabled(flagKey: string, userId?: string): boolean {
const flag = this.flags.get(flagKey);
if (!flag) return false;
switch (flag.status) {
case 'enabled':
return true;
case 'disabled':
return false;
case 'percentage':
if (!userId || !flag.rolloutPercentage) return false;
// Deterministic hash for consistent user experience
const hash = this.hashUserId(userId, flagKey);
return hash < flag.rolloutPercentage;
case 'user-segment':
if (!userId) return false;
return flag.targetUsers?.includes(userId) ?? false;
default:
return false;
}
}
private hashUserId(userId: string, flagKey: string): number {
let hash = 0;
const str = `${userId}:${flagKey}`;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32-bit integer
}
return Math.abs(hash) % 100;
}
}
// Usage in application code
const featureFlags = new FeatureFlagService();
function renderCheckout(userId: string) {
if (featureFlags.isEnabled('new-checkout-flow', userId)) {
return renderNewCheckout();
}
return renderLegacyCheckout();
}
// Deployment Strategies
type DeploymentStrategy = {
name: string;
description: string;
riskLevel: 'low' | 'medium' | 'high';
rollbackTime: string;
resourceCost: string;
};
const deploymentStrategies: DeploymentStrategy[] = [
{
name: 'Blue-Green',
description: 'Maintain two identical environments. Deploy to inactive (green), switch traffic from active (blue) to green.',
riskLevel: 'low',
rollbackTime: 'Seconds (switch back to blue)',
resourceCost: 'High (2x infrastructure)'
},
{
name: 'Canary',
description: 'Route a small percentage (1-5%) of traffic to the new version. Gradually increase if metrics look good.',
riskLevel: 'low',
rollbackTime: 'Seconds (route all traffic to old version)',
resourceCost: 'Medium (small additional capacity)'
},
{
name: 'Rolling',
description: 'Gradually replace old instances with new ones, one at a time or in batches.',
riskLevel: 'medium',
rollbackTime: 'Minutes (redeploy old version)',
resourceCost: 'Low (no extra infrastructure)'
},
{
name: 'Big Bang',
description: 'Replace everything at once during a maintenance window.',
riskLevel: 'high',
rollbackTime: 'Minutes to hours',
resourceCost: 'Low'
}
];
Release Checklist
Pre-Release Checklist
- ☐ All stories in the release are "Done" (meet DoD)
- ☐ All automated tests pass (unit, integration, E2E)
- ☐ Performance testing completed — no regressions
- ☐ Security scan completed — no critical/high vulnerabilities
- ☐ Database migrations tested on staging with production-like data
- ☐ Feature flags configured for gradual rollout
- ☐ Rollback plan documented and tested
- ☐ Monitoring and alerts configured
- ☐ Release notes written and distributed
- ☐ On-call engineer identified for the release window
- ☐ Stakeholders notified of release schedule
Rollback Procedures
- Define Rollback Triggers: Error rate > 1%, latency > 2x baseline, critical bug reported by 5+ users
- Automate Rollback: One command or button to revert. No manual steps during an emergency.
- Test Rollback Regularly: Practice rolling back in staging. An untested rollback plan is not a plan.
- Database Considerations: Backward-compatible schema migrations only. Never deploy a breaking migration.