← Back to Blog

TypeScript CI Quality Gates: The Complete Checklist (2026)

By Nark Team

A complete TypeScript CI quality gate runs type checking, linting, formatting, tests, security scanning, and dependency error handling on every pull request. Most TypeScript projects cover the first four. The last two — security scanning and dependency error handling — are where production crashes and vulnerabilities slip through.

Quick Answer: The six CI quality gates for TypeScript are: (1) tsc --noEmit, (2) ESLint, (3) Prettier, (4) Vitest/Jest, (5) security scanning (Semgrep or npm audit), and (6) Nark for dependency error handling. Here's a ready-to-copy GitHub Actions workflow that runs all six.


The Six TypeScript CI Quality Gates

Gate 1: TypeScript Type Checking

npx tsc --noEmit

Catches type mismatches, missing properties, null dereferences (with strictNullChecks), and structural errors. Every TypeScript project should run this in CI — not just at deploy time.

Common mistake: Running only next build or tsc for production builds, not in CI on PRs. Type errors that compile in dev but fail in prod catch you at the worst time.

Gate 2: ESLint

npx eslint src --ext .ts,.tsx --max-warnings 0

Catches language-level anti-patterns, unhandled promises (no-floating-promises), incorrect async patterns, and any team-specific rules. The --max-warnings 0 flag ensures warnings don't silently accumulate.

Essential plugins for TypeScript:

  • @typescript-eslint/eslint-plugin — TypeScript-specific rules
  • eslint-plugin-import — import ordering and resolution
  • @typescript-eslint/no-floating-promises — catches unawaited async calls

Gate 3: Prettier

npx prettier --check src

Consistent formatting prevents style-based review comments and merge conflicts. The --check flag exits with code 1 if any file needs reformatting.

Gate 4: Tests

npx vitest run --coverage

Catches regressions in business logic. Coverage thresholds (--coverage.thresholds.lines=80) prevent coverage from dropping silently.

Testing libraries by use case:

  • Unit tests: Vitest (fast, TypeScript-native) or Jest
  • Integration tests: Vitest with database fixtures
  • E2E tests: Playwright or Cypress
  • API tests: Supertest with test database

Gate 5: Security Scanning

npm audit --audit-level=high

Or with Semgrep for deeper static analysis:

npx semgrep --config p/typescript --error

npm audit finds packages with known CVEs. Semgrep detects SQL injection, hardcoded secrets, insecure crypto usage, and other security anti-patterns in your code.

Gate 6: Dependency Error Handling (Nark)

npx nark --tsconfig tsconfig.json

Catches unhandled runtime errors from npm packages. ESLint knows you have a try-catch. Nark knows whether the catch block handles the specific errors the package can throw.

This gate catches bugs that pass all five previous gates:

// Passes tsc, ESLint, Prettier, tests, and security scanning
// nark flags: StripeCardError not handled
try {
  const charge = await stripe.charges.create({ amount, currency, source });
  return charge;
} catch (error) {
  throw new Error('Payment failed'); // card decline == server error, both treated identically
}

Complete GitHub Actions Workflow

# .github/workflows/ci.yml
name: CI

on:
  pull_request:
    branches: [main, develop]
  push:
    branches: [main]

jobs:
  quality:
    name: Quality Gates
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      # Gate 1: TypeScript
      - name: TypeScript — type check
        run: npx tsc --noEmit

      # Gate 2: ESLint
      - name: ESLint — lint
        run: npx eslint src --ext .ts,.tsx --max-warnings 0

      # Gate 3: Prettier
      - name: Prettier — format check
        run: npx prettier --check src

      # Gate 4: Tests
      - name: Vitest — unit and integration tests
        run: npx vitest run --coverage

      # Gate 5: Security
      - name: npm audit — dependency vulnerabilities
        run: npm audit --audit-level=high

      # Gate 6: Dependency error handling
      - name: nark — unhandled package errors
        run: npx nark --tsconfig tsconfig.json

Checklist: Is Your CI Complete?

Before shipping to production, every PR should pass these checks:

Type safety

  • tsc --noEmit passes with strict: true in tsconfig
  • strictNullChecks: true enabled — nullable values require explicit handling
  • noUncheckedIndexedAccess: true — array/object access returns T | undefined

Code quality

  • ESLint passes with --max-warnings 0
  • @typescript-eslint/no-floating-promises enabled — catches bare async calls
  • @typescript-eslint/no-explicit-any enabled (or warnings tracked)

Formatting

  • Prettier check passes — no formatting differences

Tests

  • Unit tests pass
  • Integration tests pass (with test database)
  • Coverage above threshold (recommend ≥80% lines)

Security

  • npm audit clean at high/critical severity
  • No hardcoded secrets (Semgrep or git-secrets pre-commit hook)

Dependency error handling

  • npx nark passes — all npm package calls have correct error handling
  • New packages added to project have profiles checked

Why Most Projects Are Missing Gate 6

The first five gates are well-established in TypeScript CI guides, tutorials, and boilerplate repositories. Gate 6 — dependency error handling — is rarely included because the tool for it only recently became available.

The result is a gap that no other gate covers:

Bug typetscESLintTestsNark
Wrong argument type
Unawaited promise
Missing test coverage
Unhandled axios network error❌ (unless you test it)
Missing Prisma P2002 handler❌ (unless you test it)
Redis without error handler

TypeScript types describe API surfaces. They don't describe runtime errors. Tests cover what you write tests for. Nark covers what the package's profile specifies — independent of whether you thought to test it.


Quick Setup: Add Nark to an Existing CI Pipeline

If you already have a GitHub Actions workflow, add Nark as a single step:

- name: nark — dependency error handling
  run: npx nark --tsconfig tsconfig.json

For monorepos with multiple tsconfigs:

- name: nark — scan all packages
  run: |
    npx nark --tsconfig apps/api/tsconfig.json
    npx nark --tsconfig apps/web/tsconfig.json
    npx nark --tsconfig packages/shared/tsconfig.json

For projects where you want only errors (not warnings) to fail CI:

- name: nark — scan with error-only threshold
  run: npx nark --tsconfig tsconfig.json --min-severity error

Packages Covered by Nark

Nark ships with profiles for 160+ npm packages. The packages most likely to have missing error handling in a typical TypeScript SaaS project:

PackageCommon missing handlers
axiosAxiosError network errors, error.response null check
@prisma/clientP2002 (unique), P2025 (not found), connection errors
stripeStripeCardError, StripeRateLimitError
ioredis.on('error') handler required
pgConnection errors, query errors
@anthropic-ai/sdkRateLimitError, APIConnectionError
openaiRateLimitError, APIConnectionError, AuthenticationError
nodemailerSMTP errors, authentication failures

Frequently Asked Questions

In what order should CI gates run?

Type checking first (fast, catches most errors). Then linting. Then formatting. Then tests (slowest). Security and Nark can run in parallel with tests. Early-failing fast gates save time when there are basic errors.

Should I run Nark on every commit or only on PRs?

PRs are the right default — that's when you want to block merges. Running on every push to main is useful as a secondary check. No need to run on every local commit (pre-commit hooks slow down development).

What if Nark reports violations on existing code (not new changes)?

Use --min-severity error to only block on errors initially, then clean up warnings over time. Or use Nark's --changed-only mode (available in newer versions) to only check files changed in the PR.

How do I add Nark profiles for packages that aren't in the corpus yet?

The nark-corpus is open source (CC-BY-NC-4.0). You can contribute profiles or file issues to request coverage for specific packages.


Try It Now

npx nark --tsconfig ./tsconfig.json

Add it to your CI pipeline as the sixth quality gate. It catches the class of production errors that type checking, linting, and tests routinely miss.