Concept
Continuous Integration (CI) vs Continuous Delivery (CD)
- Continuous Integration (CI): Automating the process of merging developer code. Every PR triggers pipelines that lint, typecheck, format-check, and run unit/integration tests to ensure no regressions enter the main branch.
- Continuous Delivery/Deployment (CD): Automating release compilation and distribution. CD deploys the validated code to staging or production CDNs.
Pipeline Stages & Parallelization
A standard frontend CI/CD pipeline consists of sequential and parallel stages:
┌──────────────────────┐
│ Git Commit │
└──────────┬───────────┘
▼
┌──────────────────────┐
│ Install Deps │
└──────────┬───────────┘
┌────────────────┼────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Lint & │ │ Typecheck │ │ Unit Tests │
│ Format │ │ (tsc) │ │ (Jest/Vitest)
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└────────────────┼────────────────┘
▼
┌──────────────────────┐
│ Build Asset │
└──────────┬───────────┘
▼
┌──────────────────────┐
│ Deploy Preview │
└──────────────────────┘- Install: Fetch and cache project dependencies (using lockfiles to guarantee exact versions).
- Lint & Typecheck (Parallel): Execute ESLint, Prettier check, and
tsc --noEmitconcurrently. - Test (Parallel): Execute unit tests (Vitest/Jest) and integration tests.
- Build: Compile production assets (HTML/JS/CSS minification, source maps).
- Deploy: Push build artifacts to CDN edge networks.
Preview Deployments
One of the most valuable CD innovations is Preview Deployments (popularized by Vercel, Netlify, and Cloudflare).
For every Pull Request, the pipeline builds a standalone version of the application and deploys it to a unique temporary URL (e.g. https://my-app-pr-42.vercel.app). This allows developers, designers, and QA teams to test changes in an isolated, live environment before merging to the main branch.
Common Mistakes
1. Re-installing package dependencies in every stage
Fetching node_modules from npm multiple times inside the same pipeline run wastes minutes. Always cache your package manager's cache directory (e.g. .pnpm-store or Yarn cache) and share the dependency folder across jobs.
2. Not pinning dependency versions
Using loose ranges (like "react": "^19.0.0") in package.json without committing the lockfile (e.g. package-lock.json or pnpm-lock.yaml) can cause CI builds to break randomly when a library publishes a patch version containing regressions. Always commit lockfiles.
Best Practices
- Build Once, Deploy Many: Compile the build once and deploy that exact zip archive to staging first. After approval, promote the same zip to production. Do not compile a second time, as build hashes can drift.
- Fail Fast: Put fast checks (linting, typechecking) at the front of the pipeline. Let them run before launching slow, expensive browser end-to-end (Cypress/Playwright) tests.
- Cache Node Modules: Use native pipeline actions (e.g.,
actions/setup-nodecaching options) to cache dependencies between workflow runs.
