|$ curl https://forge-ai.dev/api/markdown?path=docs/ci/continuous-integration
$cat docs/continuous-integration.md
updated Recently·30 min read·published

Continuous Integration

CI/CDAutomationIntermediate
Introduction

Continuous Integration (CI) is a development practice where developers frequently merge their code changes into a shared repository — often multiple times a day. Each merge triggers an automated build and test suite to detect integration errors as early as possible.

CI is the first line of defense against regressions. A well-tuned CI pipeline catches bugs, style violations, type errors, and performance regressions before they ever reach a reviewer or production environment.

Core Principles

CI is built on a few foundational practices that every team should adopt:

PrincipleDescriptionImpact
Frequent CommitsPush small, focused changes dailyReduces merge conflicts, isolated bugs
Automated BuildEvery commit triggers a reproducible buildEliminates "works on my machine"
Automated TestsUnit, integration, and lint checks run automaticallyCatches regressions within minutes
Fast FeedbackPipeline should complete in under 10 minutesMaintains developer flow state
Main Branch is StableBroken builds block further mergesEnforces quality gating
Pre-Commit Hooks (Husky)

Pre-commit hooks catch issues before code is even committed. They run linting, formatting, and type-checking locally, providing instant feedback without consuming CI resources.

.husky-setup.sh
Bash
1# Install Husky in your project
2npx husky init
3
4# Add a pre-commit hook to lint staged files
5npx husky add .husky/pre-commit "npx lint-staged"
6
7# .lintstagedrc.json example
8{
9 "*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
10 "*.{css,scss}": ["stylelint --fix", "prettier --write"],
11 "*.{json,md,yaml}": ["prettier --write"]
12}
13
14# Add commit-msg hook for conventional commits
15npx husky add .husky/commit-msg "npx --no -- commitlint --edit $1"

info

Combine Husky with lint-staged to only lint files that changed in the current commit. This keeps pre-commit hooks fast even in large codebases — running lint on every file would take minutes instead of seconds.
Branch Protection Rules

Branch protection rules enforce CI discipline. They prevent direct pushes to main, require pull requests, mandate status checks, and ensure branches are up to date.

RuleSettingPurpose
Require PRRequiredPrevents direct pushes to protected branches
Required Approvals1-2 reviewersEnsures code review before merge
Status ChecksAll passingBlocks merge if CI fails
Up-to-DateRequiredBranch must be based on latest main
Conversation ResolutionRequiredAll comments must be resolved before merge
branch-protection.yml
YAML
1# GitHub branch protection rule (via API or UI)
2# Path: Settings > Branches > Add rule
3
4Branch name pattern: main
5Settings:
6 - Require a pull request before merging
7 - Require approvals: 1
8 - Dismiss stale reviews: true
9 - Require review from Code Owners: true
10 - Require status checks before merging
11 - Require branches to be up-to-date: true
12 - Status checks:
13 - "continuous-integration / lint"
14 - "continuous-integration / test"
15 - "continuous-integration / build"
16 - "codecov/project"
17 - Require conversation resolution: true
18 - Do not allow bypassing the above settings
CI Pipeline Stages

A robust CI pipeline is composed of sequential stages. Each stage filters out defects, so later stages run faster and more predictably.

1. Install Dependencies

Clean install of dependencies using lockfiles. Cache between runs for speed.

install.sh
Bash
1npm ci # Clean install from package-lock.json
2# or
3yarn install --frozen-lockfile # Yarn equivalent

2. Lint & Format

Enforce code style and catch obvious errors before running expensive tests.

lint.sh
Bash
1npm run lint # ESLint or equivalent
2npm run format:check # Prettier check (not autofix in CI)
3npm run typecheck # TypeScript checking (tsc --noEmit)

3. Unit Tests

Fast, isolated tests that validate individual functions and components.

test-unit.sh
Bash
1npm run test:unit # Vitest, Jest, or Mocha
2npm run test:coverage # With coverage reporting

4. Build

Verify the application builds successfully. Catches bundling errors and missing dependencies.

build.sh
Bash
1npm run build # Next.js, Vite, or Webpack build

5. Integration & E2E Tests

Slower tests that validate the system as a whole. Run against a build artifact or preview deployment.

test-e2e.sh
Bash
1npm run test:integration # API/integration tests
2npm run test:e2e # Playwright or Cypress

best practice

Parallelize independent stages where possible. For example, lint and unit tests can run simultaneously. Only build and integration tests should be sequential. Use CI matrix strategies to run tests across multiple Node versions or operating systems.
CI Provider Comparison

Choosing the right CI provider depends on your team size, project complexity, and budget. Here is a comparison of the three most popular options:

FeatureGitHub ActionsTravis CICircleCI
PricingFree: 2000 min/moFree: limited (now paid-only for new users)Free: 6000 min/mo (1 user)
ConfigurationYAML in .github/workflowsYAML in .travis.ymlYAML in .circleci/config.yml
Matrix BuildsBuilt-in (strategy.matrix)Built-in (matrix)Built-in (matrix)
Cacheactions/cache@v3cache: directoriessave/restore_cache
Self-HostedYes (runners)Yes (Travis CI Enterprise)Yes (self-hosted runners)
MacOS/WindowsYesYes (paid)Yes (paid)
MarketplaceExtensive (20K+ actions)LimitedOrbs (3rd-party)
Best ForGitHub-hosted projectsOpen-source, legacy projectsComplex pipelines, large teams
ci-pipeline.yml
YAML
1# GitHub Actions — Full CI Pipeline Example
2name: CI Pipeline
3on:
4 push:
5 branches: [main, develop]
6 pull_request:
7 branches: [main]
8
9jobs:
10 lint:
11 runs-on: ubuntu-latest
12 steps:
13 - uses: actions/checkout@v4
14 - uses: actions/setup-node@v4
15 with:
16 node-version: 20
17 cache: npm
18 - run: npm ci
19 - run: npm run lint
20 - run: npm run typecheck
21
22 test:
23 runs-on: ubuntu-latest
24 steps:
25 - uses: actions/checkout@v4
26 - uses: actions/setup-node@v4
27 with:
28 node-version: 20
29 cache: npm
30 - run: npm ci
31 - run: npm run test:unit -- --coverage
32 - uses: codecov/codecov-action@v3
33
34 build:
35 runs-on: ubuntu-latest
36 needs: [lint, test]
37 steps:
38 - uses: actions/checkout@v4
39 - uses: actions/setup-node@v4
40 with:
41 node-version: 20
42 cache: npm
43 - run: npm ci
44 - run: npm run build
45 - uses: actions/upload-artifact@v4
46 with:
47 name: build-output
48 path: .next/
🔥

pro tip

Use actions/cache to persist node_modules and .next/cache between runs. This reduces install time from 60s to under 5s. Pin the cache key to your lockfile hash so it invalidates on dependency changes.
Status Checks & Gating

Status checks report the result of CI jobs back to the pull request. They appear as green checkmarks, red X's, or yellow dots next to each commit.

Required status checks must pass before a PR can merge. Configure them in your repository settings under Settings > Branches > Branch protection rules.

Check NameStatusRequired
continuous-integration/lint✓ PassingYes
continuous-integration/test✓ PassingYes
continuous-integration/build✓ PassingYes
codecov/project⚠ PendingNot required

warning

Do not mark coverage checks as required unless you have a well-defined coverage target that your team consistently meets. A flaky coverage check that blocks merges will frustrate developers and lead to workarounds that defeat the purpose of CI.
CI Best Practices
Keep pipelines fast — aim for under 10 minutes total. Split long-running jobs into parallel steps.
Use deterministic dependency installs (npm ci, not npm install) to ensure reproducibility.
Cache dependencies and build artifacts between runs. Invalidate caches when lockfiles change.
Pin CI runner versions (ubuntu-latest can shift underneath you — prefer ubuntu-22.04).
Fail fast: order stages so the fastest checks (lint) run before the slowest (E2E tests).
Use concurrency controls to cancel redundant runs on the same branch (new push cancels prior).
Store CI artifacts (test reports, screenshots, logs) for debugging failed builds.
Run CI on both push and pull_request triggers to catch branch and merge-queue issues.
Secret scanning: use CI to detect accidentally committed credentials (e.g., truffleHog, Gitleaks).
Monitor CI health: track success rate, average duration, and queue wait times.
$Blueprint — Engineering Documentation·Section ID: CI-01·Revision: 1.0