Ship it to production with previews and safe rollout
Continues from the last build: A fully instrumented build of it, Web Vitals and errors reporting straight to your dashboards, that still only exists on your laptop.
Every rung so far has made it smarter in the browser, but right now the only way anyone else sees it is a screen share.
What you'll build
A production deployment of it on a CDN host with automatic PR preview URLs, immutable hashed-asset caching with a correctly-revalidated index.html, environment-scoped config that never leaks secrets into the client bundle, a client-side feature flag gate with a redeploy-free kill switch, and a written rollback plan you have actually rehearsed.
See how we teach, before you sign up
You don't just get code dumped on you. Every starter file and every solution is explained line-by-line, in plain English. Here's one real file from this project:
name: Deploy Pulse
on:
pull_request:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm run build
Reading this file
pull_request:this trigger fires for every PR, which is where the preview-deploy job will hook inbranches: [main]production deploys should only ever run off the main branch, never a feature branchnode-version: 20pin the Node version so CI matches local dev and Vite behaves identically in both placesrun: npm run buildproduces the static dist folder that gets deployed, nothing runs on a server after this step
Builds on every push and PR, but does not deploy anywhere yet. Milestone 2 adds the preview and production deploy jobs.
That's 1 of 7 explained code blocks in this single project.
The build, milestone by milestone
- 1
Produce an immutable, cache-correct static build
4 guided stepsVite hashes every asset filename on build, so an asset URL never changes meaning. That means it is safe to cache assets forever, but index.html (which references those hashed filenames) must never be cached, or users keep loading an old shell that points at files the CDN already replaced.
- 2
Wire CI so every pull request gets a live preview URL
4 guided stepsA diff on GitHub cannot show you a hover state, an animation, or how a real screen reader announces the new aria-live region you added in an earlier rung. A live preview URL turns 'looks fine to me' into an actual click-through review.
- 3
Configure environments without leaking secrets into the client bundle
4 guided stepsEverything in `import.meta.env` that starts with VITE_ gets bundled straight into the client JavaScript that ships to every visitor's browser. Anything that is not meant to be public, a real API secret, a deploy token, must never carry that prefix or it ends up readable in devtools by anyone.
- 4
Add a client feature flag gate with a kill switch that needs no server
4 guided stepsA backend-driven flag service is its own project. The frontend-only version, a static JSON file on the same CDN as the app, gets you 90% of the value: flipping a flag off is editing one file and redeploying it, which takes seconds and needs no server at all.
- 5
Write the rollback plan and ship the release checklist
4 guided stepsA rollback plan nobody has ever executed is a guess, not a plan. Because every deploy on an immutable-asset host is additive, rolling back is almost always 'promote the previous deployment', but that only works if you never overwrite or delete a previous deploy's asset folder.
What's inside when you start
You'll walk away with
This is portfolio-grade. Build it free.
Sign up to unlock every milestone step-by-step, the code skeletons, full reference solutions, and checkable tasks, with your progress saved as you build.
Start building