6 npm Packages Every TypeScript Project Should Run in CI
By Nark Team
Every TypeScript project needs these six tools running in CI: the TypeScript compiler for type checking, ESLint for linting, Prettier for formatting, Vitest for testing, a security scanner, and Nark for dependency error handling. Most projects run the first four. The last two are where production incidents and security vulnerabilities slip through code review.
Quick Answer: TypeScript + ESLint + Prettier + Vitest covers types, style, and logic. Add
npm audit(or Semgrep) for security andnarkfor dependency error handling. Here is a ready-to-copy GitHub Actions workflow that runs all six.
1. TypeScript (typescript)
npx tsc --noEmit
TypeScript's compiler is the foundation. It catches type mismatches, missing properties, structural incompatibilities, and null dereferences (with strictNullChecks).
CI step:
- name: TypeScript type check
run: npx tsc --noEmit
Key tsconfig settings for maximum type safety:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true
}
}
strict enables strictNullChecks, noImplicitAny, and other important rules. noUncheckedIndexedAccess catches array[i] accesses that may be undefined. exactOptionalPropertyTypes prevents accidentally assigning undefined to optional properties.
2. ESLint (eslint + @typescript-eslint)
npx eslint src --ext .ts,.tsx --max-warnings 0
ESLint enforces code quality rules beyond what TypeScript checks. The @typescript-eslint plugin adds TypeScript-specific rules that are particularly valuable.
Install:
npm install --save-dev eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser
Minimal .eslintrc.json for TypeScript:
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"rules": {
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }]
}
}
@typescript-eslint/no-floating-promises is critical — it catches async function calls with no await and no .catch(). Without this rule, unhandled promise rejections can crash Node.js processes silently.
CI step:
- name: ESLint
run: npx eslint src --ext .ts,.tsx --max-warnings 0
3. Prettier (prettier)
npx prettier --check src
Prettier enforces consistent code formatting. Running it in CI (check mode) prevents formatting drift and eliminates style-based code review comments.
Install:
npm install --save-dev prettier
Minimal .prettierrc:
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100
}
CI step:
- name: Prettier
run: npx prettier --check src
4. Vitest (vitest)
npx vitest run
Vitest runs your unit and integration tests. It's faster than Jest for TypeScript projects (native ESM support, TypeScript without Babel), and shares configuration with Vite if you use it.
Install:
npm install --save-dev vitest @vitest/coverage-v8
vitest.config.ts:
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
environment: 'node',
coverage: {
provider: 'v8',
reporter: ['text', 'lcov'],
thresholds: {
lines: 80,
},
},
},
});
CI step:
- name: Vitest
run: npx vitest run --coverage
If your team prefers Jest, the CI step is the same structure: npx jest --coverage.
5. Security Scanner (npm audit or semgrep)
npm audit --audit-level=high
npm audit checks your dependency tree against the npm security advisory database. It finds packages with known CVEs before they reach production.
CI step:
- name: Security audit
run: npm audit --audit-level=high
For deeper static analysis — SQL injection, hardcoded secrets, insecure crypto — add Semgrep:
- name: Semgrep — security patterns
uses: returntocorp/semgrep-action@v1
with:
config: p/typescript
p/typescript is Semgrep's curated TypeScript security ruleset. It catches eval(), prototype pollution, SQL injection, and other patterns.
npm audit and Semgrep are complementary: audit finds vulnerable packages, Semgrep finds vulnerable code patterns.
6. Nark — Dependency Error Handling
npx nark --tsconfig tsconfig.json
Nark is the quality gate that the first five tools miss. It checks whether your code correctly handles the runtime errors that your npm dependencies can throw.
What Nark catches that the other five tools miss:
// Passes tsc ✅, ESLint ✅, Prettier ✅, Vitest ✅ (no test for this), npm audit ✅
// nark: FAILS — axios network error case not handled
async function getUser(id: string): Promise<User> {
try {
const response = await axios.get<User>(`/api/users/${id}`);
return response.data;
} catch (error) {
// error.response is undefined on network errors
// accessing it crashes with TypeError
throw new Error(`API error: ${error.response.status}`);
}
}
Nark knows that axios.get() throws AxiosError with three distinct shapes, that error.response can be undefined on network failures, and that the above code will crash at error.response.status when there's a timeout or DNS failure.
Install: No install required. npx nark runs directly.
CI step:
- name: nark — dependency error handling
run: npx nark --tsconfig tsconfig.json
Packages covered: 160+ npm packages, including axios, @prisma/client, stripe, ioredis, pg, openai, @anthropic-ai/sdk, nodemailer, jsonwebtoken, and more.
The Complete Workflow
# .github/workflows/ci.yml
name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
ci:
name: CI
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: TypeScript type check
run: npx tsc --noEmit
- name: ESLint
run: npx eslint src --ext .ts,.tsx --max-warnings 0
- name: Prettier
run: npx prettier --check src
- name: Vitest
run: npx vitest run --coverage
- name: npm audit
run: npm audit --audit-level=high
- name: nark — dependency error handling
run: npx nark --tsconfig tsconfig.json
What Each Tool Catches (No Overlap)
| Category | Tool | What It Catches |
|---|---|---|
| Type safety | TypeScript | Wrong types, missing properties, null dereferences |
| Code quality | ESLint | Language anti-patterns, unhandled promises, unused vars |
| Formatting | Prettier | Inconsistent whitespace, quotes, trailing commas |
| Logic regressions | Vitest | Test failures, coverage drops |
| Vulnerable packages | npm audit | CVEs in dependencies |
| Runtime error handling | Nark | Incorrect/missing npm package error handling |
These six tools cover six distinct categories with zero overlap. Missing any one leaves a gap that the other five cannot fill.
Rollout Strategy for Existing Projects
If you're adding these to an existing project that has accumulated issues, use a phased rollout to avoid a wall of failing CI:
Week 1: TypeScript (fix all type errors), Prettier (format everything)
Week 2: ESLint (add rules incrementally, fix violations)
Week 3: Vitest (write tests for critical paths, set initial coverage threshold)
Week 4: npm audit (resolve or document accepted vulnerabilities)
Week 5: Nark with --min-severity error (address errors, note warnings for later)
Week 6+: Nark without min-severity filter, fix all warnings
Each week adds one gate. The team adapts before the next gate goes live.
Frequently Asked Questions
Should I run all six on every commit?
PR-based CI (on pull_request) is the right default. Pre-push hooks are optional for fast tools (TypeScript, ESLint, Prettier). Vitest and Nark are better suited to CI than pre-commit hooks to avoid slowing down local development.
Are there lighter alternatives to Vitest?
Vitest is already fast. If your test suite is slow, the issue is usually database setup/teardown in integration tests, not Vitest itself. Consider --reporter=verbose to identify slow tests.
How do I handle Nark violations on packages we don't fully control?
Use exclusion patterns in .nark/config.yaml for vendor code, generated files, or test mocks. The Nark scan should cover your application code, not third-party code.
Can I add these incrementally without breaking CI?
Yes. Add continue-on-error: true to any step while you fix violations, then remove it once clean. Don't use --max-warnings 0 on ESLint or --min-severity error on Nark until you're ready to fail on everything.
Try It Now
Run Nark locally to see what it finds:
npx nark --tsconfig ./tsconfig.json
Then add to CI:
- name: nark — dependency error handling
run: npx nark --tsconfig tsconfig.json
Nark is the sixth quality gate that completes your TypeScript CI setup.