
Zero‑Downtime Angular Upgrades 10–15 ➜ 20: Deprecations, Tests, Canary Rollouts, and Fast Rollbacks
A battle‑tested upgrade playbook from enterprise Angular programs—ship Angular 20 without blinking production.
Zero‑downtime Angular upgrades are a delivery product. Scope it, instrument it, and make rollback a one‑liner.Back to all posts
I’ve shipped high‑stakes upgrades where downtime wasn’t an option—a global entertainment company workforce tools during payroll close, a broadcast media network VPS scheduling in primetime windows, and Charter’s ad analytics dashboards mid‑campaign. This is the zero‑drama path I use to move Angular 10–15 apps to 20 and keep prod calm.
The Stakes: a Jittery Dashboard and a CFO Watching Revenue
Real scene from enterprise rollouts
At a leading telecom provider, a jittery dashboard during a rollout meant millions in ad pacing decisions got delayed. At a broadcast media network, we had five minutes between live scheduling windows to cut over. United kiosks had to stay online—even offline—while we swapped builds in airports. Zero downtime isn’t a nice‑to‑have; it’s table stakes.
If you need a senior Angular engineer or Angular consultant to own this, I’ve done it repeatedly with Angular 20+, Nx, PrimeNG, Firebase, Docker, and CI/CD on GitHub Actions/Jenkins/Azure DevOps.
Why Angular 10–15 Apps Break on the Way to 20
High‑risk deprecations to plan around
Deprecations are predictable if you inventory them early. Don’t refactor modules to standalone or migrate NgRx to Signals mid‑upgrade unless required. You’re upgrading the platform first, not rebuilding the app. We’ll verify SSR hydration and routing without scope creep.
Builders: move from legacy webpack builders to the application (Vite) builder.
Test runner: Karma/Jasmine deprecated; prefer Jest or Angular’s built‑in runner.
TypeScript/Node: Angular 20 requires modern TS/Node; align engines.
RxJS: toPromise removed, scheduler changes—codemods help.
ESLint: migrate from TSLint if still present.
SSR + hydration: modern hydration paths require correct providers and stable initial state.
Router and standalone APIs: avoid mixing deep refactors during the upgrade.
Plan the Zero‑Downtime Upgrade
Define SLOs and guardrails
Write the SLOs down. Gate promotion on these numbers. I use Angular DevTools locally and Lighthouse CI in PRs, plus GA4/Firebase Analytics to watch real RUM during canary.
Core Web Vitals deltas ≤ 5%.
Error budget: ≤ 0.5% new 5xx and ≤ 1% client error delta.
Rollback SLA: ≤ 5 minutes to restore N‑1.
Monitoring: Sentry releases + OpenTelemetry traces in CI and canary.
Inventory and freeze scope
In a global entertainment company’s employee tracking tools, this stopped the urge to "fix the UI while we’re here"—that’s how timelines slip.
List all apps/libs in Nx or workspace.
Map builders, test runner, linting, SSR, and hosting.
Freeze UX features; only platform changes allowed.
Implementation Steps: Commands and Config
1) Align engines and package managers
Pin Node/PNPM versions so CI and dev match.
// package.json
{
"engines": {
"node": ">=20 <21",
"pnpm": "^9"
}
}2) Major-by-major updates (or Nx migrate)
# Angular CLI path, hop-by-hop (example from 14 -> 20)
ng update @angular/core@15 @angular/cli@15 --force
ng update @angular/core@16 @angular/cli@16 --force
ng update @angular/core@17 @angular/cli@17 --force
ng update @angular/core@18 @angular/cli@18 --force
ng update @angular/core@19 @angular/cli@19 --force
ng update @angular/core@20 @angular/cli@20 --force
# Nx workspaces
pnpm dlx nx migrate latest
pnpm install
pnpm dlx nx migrate --run-migrationsCommit per hop; run and fix codemods; keep tests green at each step.
3) Switch to the application (Vite) builder
// angular.json (excerpt)
{
"projects": {
"app": {
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/app",
"optimization": true,
"serverRouting": true
}
}
}
}
}
}Biggest perf win and deprecation reducer.
Check custom webpack logic—replace with Vite plugins if needed.
4) RxJS 7 cleanups
import { firstValueFrom } from 'rxjs';
async function loadUser(api$: Observable<User>) {
const user = await firstValueFrom(api$);
return user;
}Remove toPromise; use firstValueFrom/lastValueFrom.
Prefer pipeable operators and strict types.
5) Tests you can trust
pnpm add -D jest @types/jest jest-preset-angular
npx jest --init// example.spec.ts
it('renders dashboard KPI', async () => {
const { fixture } = await render(DashboardComponent);
expect(fixture.nativeElement.querySelector('[data-kpi]')!.textContent)
.toContain('On Target');
});Move from Karma to Jest or Angular test runner.
Add component tests with TestBed + Harnesses; keep fast feedback.
6) SSR and hydration sanity
bootstrapApplication(AppComponent, {
providers: [
provideClientHydration(),
// feature flags via environment or Remote Config
]
});Keep SSR API surface stable between N-1 and N.
Verify provideClientHydration and TransferState usage.
CI/CD with Canary Traffic and Automatic Rollback
GitHub Actions: build, test, canary 10%, promote
name: deploy
on:
push:
branches: [main]
jobs:
build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
with: { version: 9 }
- uses: actions/setup-node@v4
with: { node-version: 20, cache: 'pnpm' }
- run: pnpm install --frozen-lockfile
- run: pnpm run test:ci && pnpm run e2e:ci
- run: pnpm run build:ssr
- run: docker build -t gcr.io/acct/app:${{ github.sha }} .
- run: docker push gcr.io/acct/app:${{ github.sha }}
canary:
needs: build-test
runs-on: ubuntu-latest
steps:
- name: Roll out 10% on Cloud Run
run: |
gcloud run services update app \
--image gcr.io/acct/app:${{ github.sha }} \
--set-traffic app-REV=${{ github.sha }}=10,current=90
- name: Health gate
run: pnpm run health:check # checks Sentry, synthetic, CWV budgets
promote:
if: success()
needs: canary
runs-on: ubuntu-latest
steps:
- name: 100% traffic
run: gcloud run services update-traffic app --to-revisions app-REV=${{ github.sha }}=100Publish N and N-1 images; tag with Git SHA.
Gate promotion on health checks (Sentry errors, synthetic pings, CWV).
Instant rollback
# Rollback in < 2 minutes
LAST_GOOD=$(gcloud run services describe app --format='value(status.traffic.statuses[0].revisionName)')
gcloud run services update-traffic app --to-revisions ${LAST_GOOD}=100Always keep last good SHA and image tag.
DB migrations must be backward compatible (expand/contract).
Feature Flags and Safe Migrations
Flag risky code paths
export const environment = {
upgrade20Enabled: true,
useNewHydration: true,
};
if (!environment.upgrade20Enabled) {
// fall back to N-1 stable behavior
}Use env flags or Firebase Remote Config for runtime flips.
Include kill switches for SSR routes and heavy dashboards.
Schema change pattern
This pattern kept a broadcast media network VPS scheduling fully available while we introduced Angular 17 SSR and later stepped to 20.
Expand: add new columns/APIs while old readers still work.
Migrate data in background.
Contract: remove old fields after 2 releases.
Test Strategy that Catches Real Regressions
What I require before production traffic
At an insurance technology company telematics, this suite caught a hydration mismatch that only occurred with empty API responses—saved us a hotfix window.
Unit tests: >80% lines on critical libs.
Component tests: Harnesses on all data‑heavy widgets.
E2E smoke: login, 3 golden journeys, logout.
Visual diff: critical routes via Percy/Chromatic.
Synthetic SSR: fetch two SSR pages and compare markup signatures.
Accessibility: AXE CI at least on entry routes.
When to Hire an Angular Developer for Legacy Rescue
Bring in help if you see these signals
If you need an Angular expert who has done zero‑downtime upgrades at a global entertainment company, Charter, a broadcast media network, and United, I’m available as a remote Angular contractor. We can scope an assessment in a week and ship your upgrade in 4–8 weeks, depending on surface area.
Multiple Angular majors behind and custom webpack hacks.
Karma/TSLint still in play; flaky e2e; no SSR health checks.
No rollback story beyond “rebuild and redeploy”.
Tense upgrade windows tied to revenue or safety.
Mini Case Study: Blue‑Green with Airline Kiosks
a major airline hardware constraints
We containerized the SSR layer and simulated printers, scanners, and card readers in Docker to test thousands of flows without actual kiosks. A weighted cutover let us expose 5% of internal kiosks, watch telemetry, then promote in minutes. Exponential retry logic and typed event schemas ensured no lost transactions.
Offline‑tolerant flows with Docker‑based hardware simulation.
Blue‑green swap with zero kiosk downtime, rollback in <5 minutes.
Wrap‑Up: Measure, Then Ship
What to instrument next
Zero‑downtime upgrades to Angular 20 are boring when planned well. Keep N‑1 hot, gate on tests and health, and make rollback a one‑liner. If you need help, hire an Angular developer who treats upgrades like a delivery product, not a weekend chore.
Lighthouse CI budgets with hard fails.
Sentry release adoption + regression alerts.
OpenTelemetry spans for SSR TTFB and route hydration.
GA4 funnel checks on canary vs control.
Key takeaways
- Plan upgrades around SLOs: define error budget, Core Web Vitals baselines, and rollback SLAs before touching code.
- Tackle platform deprecations first: builders (Vite), test runner, TypeScript/Node, RxJS 7, ESLint, SSR hydration.
- Use canary + feature flags: ship Angular 20 behind flags, ramp from 1–10–50–100% with automated health checks.
- Keep N-1 hot: build/publish both N and N-1 images to enable instant, lossless rollback.
- Gate on tests you trust: unit, component, e2e, and visual diffs, plus smoke checks that hit real SSR and APIs.
- Instrument everything: Sentry releases, OpenTelemetry traces, and Lighthouse CI to prove “no regression”.
- Avoid scope creep: postpone Signals/standalone refactors unless required by the upgrade.
Implementation checklist
- Freeze UX scope; upgrade platform only (builders, TypeScript, test, RxJS).
- Create upgrade branch and protect main with required checks.
- Pin Node/PNPM versions; align TypeScript with Angular 20.
- Run ng update major-by-major or Nx migrate with codemods; commit after each hop.
- Migrate builders to @angular-devkit/build-angular:application (Vite).
- Switch from TSLint/Karma to ESLint and Jest or Angular’s test runner.
- Keep N-1 SSR image and DB schema backward compatible.
- Stand up canary environment; integrate health checks + error budgets.
- Automate rollback to N-1 in one command.
- Monitor with Sentry/OTel; verify Core Web Vitals and API error rates.
Questions we hear from teams
- How long does an Angular 10–15 to 20 upgrade take?
- Plan 2–4 weeks for small apps, 4–8 weeks for enterprise dashboards with SSR. Add one week for cross‑lib upgrades. Canary typically runs 24–72 hours with automated health checks and rollbacks.
- What does a zero‑downtime rollout look like?
- Build and test Angular 20, deploy as a new revision, shift 1–10–50–100% traffic while monitoring Sentry, OTel, and CWV. Keep N‑1 image live for instant rollback. Use feature flags for risky paths.
- How much does it cost to hire an Angular developer for an upgrade?
- Most upgrades I lead land between 2–8 weeks of senior engineering time. Fixed‑scope assessments are available, followed by a milestone‑based delivery plan tied to SLOs and a rollback SLA.
- Do we need to migrate to Signals or standalone during the upgrade?
- Not necessarily. Focus on platform deprecations—builders, tests, RxJS, SSR. Schedule Signals/standalone refactors later unless a framework change requires it.
- What CI/CD tools do you use for upgrades?
- GitHub Actions or Jenkins for pipelines, Docker for SSR images, Cloud Run or Azure Web Apps for weighted rollouts, Sentry + OpenTelemetry for telemetry, and Lighthouse CI for performance budgets.
Ready to level up your Angular experience?
Let AngularUX review your Signals roadmap, design system, or SSR deployment plan.
NG Wave
Angular Component Library
A comprehensive collection of 110+ animated, interactive, and customizable Angular components. Converted from React Bits with full feature parity, built with Angular Signals, GSAP animations, and Three.js for stunning visual effects.
Explore Components