My Frontend Deployment Workflow: From Local Dev to Live Site in 2025
Local quality gates, a GitHub Actions build on Node 20, a signed artifact upload, and a guarded server rollout with nginx reload. The whole pipeline, end to end.
A deploy pipeline is not infrastructure trivia. It decides how often you ship, how scared you are to ship, and how fast you can recover when you break something. Here is the one running this site.
The four stages
Every deploy goes through four stages, in order, and each stage can refuse to let the next one run.
- Local quality gates< 30s
- GitHub Actions build (Node 20)~90s
- Artifact upload (signed)~10s
- Server rollout + nginx reload~5s
- Total commit-to-live~2m 15s
If any stage fails, the live site does not change. That is the whole game.
Local quality gates
Before a commit lands on main, three things have to pass on my machine.
Type check
A full `tsc --noEmit` on the project. Type errors are the cheapest bugs to catch and the most embarrassing ones to ship.
Lint and format
ESLint with project rules, Prettier to normalise. The point isn't perfection. The point is that nobody argues about whitespace in a PR review.
Build
A full production build runs locally. If it doesn't build on my laptop, it definitely won't build in CI, and finding out in CI wastes three minutes for no reason.
These are wired into a git pre-push hook, not pre-commit. Pre-commit slows down individual commits and trains you to bypass it. Pre-push runs once when you are ready to share work, which is exactly when you want the checks to fire.
GitHub Actions build
The CI job runs on Node 20 because that is what the server runs. Matching versions exactly removes a whole class of "works in dev, breaks in prod" failures.
The job does three things and nothing else: install dependencies from a frozen lockfile, run the production build, and upload the build output as an artifact. No deploy logic in CI. CI's job is to produce a known-good artifact. Whether to release it is a separate decision.
Signed artifact upload
The build output gets uploaded to object storage with a content-addressed name (sha-of-commit dot tar dot gz). Three reasons this matters:
1. The artifact name encodes exactly which commit it is. No "which build is in prod right now" confusion. 2. Rollback is one URL away. Point the server at a previous artifact and reload. 3. The artifact is signed, so the server can verify it actually came from CI and was not swapped out.
Server rollout with nginx reload
The server pulls the artifact, extracts it to a versioned directory (`/var/www/site/<commit-sha>`), and atomically updates a symlink (`/var/www/site/current`) to point at it. Then `nginx -s reload`.
The reload is the trick. Nginx finishes in-flight requests against the old root before serving new ones from the new root. There is no visible downtime, even mid-request. If something is broken about the new build that only shows up under traffic, I can flip the symlink back in seconds.
The pipeline is not what makes the deploy fast. It is what makes the rollback fast.
What I deliberately do not do
A few things I tried and walked away from.
- 01
Auto-deploy from main without a guard For solo work it sounds great. In practice the half-asleep commit always finds its way to prod. There is now a manual confirm step that takes me five seconds and has saved me three times.
- 02
A staging environment that mirrors prod For a portfolio site, the cost of maintaining a parallel environment is higher than the cost of catching the rare bug it would find. The artifact pipeline plus easy rollback covers 95% of what a staging environment would catch, with none of the maintenance.
- 03
Atomic database migrations on every deploy Nothing about this pipeline is wrong, but it does not run migrations. Schema changes are deployed separately and explicitly, because conflating "I shipped a UI tweak" with "I altered the production database" is how you have a bad afternoon.
The system is small on purpose. Every part of it earns its place by either making deploys faster or making recovery faster. Anything else is overhead.
Build the AI layer you'd be proud to ship.
If your roadmap has voice, copilots, RAG, or agentic flows on it, the booking link below is the right move. 30 minutes, no pitch, straight answer on whether I can help.