Add Dependency Error Checking to Your TypeScript CI in 2 Minutes
By Nark Team
Add dependency error checking to your TypeScript CI in two minutes. One npm ci step, no configuration required. Nark reads your tsconfig.json and checks every axios, Prisma, Stripe, and other npm package call for correct error handling on every pull request.
Quick Answer: Add this to your GitHub Actions workflow:
npx nark --tsconfig tsconfig.json. That's it. No config file, no signup. Nark exits 0 (clean) or 1 (violations found) and integrates into any CI pipeline that fails on non-zero exit codes.
Step 1: Run It Locally First
Before adding to CI, see what Nark finds on your codebase:
npx nark --tsconfig ./tsconfig.json
Output looks like this:
src/services/api.ts:34 — axios
[ERROR] axios.get() called without try-catch
axios throws AxiosError on non-2xx responses and network failures.
src/db/users.ts:67 — @prisma/client
[ERROR] prisma.user.create() — P2002 unique constraint not handled
PrismaClientKnownRequestError with code P2002 is thrown on duplicate
unique field values (e.g., duplicate email address).
src/lib/cache.ts:12 — ioredis
[ERROR] Redis client missing .on('error') handler
An unhandled 'error' event on an EventEmitter crashes the Node.js process.
3 violations found (3 errors, 0 warnings)
Exit code: 1
If Nark finds violations, either fix them first (recommended) or start with --min-severity warning to make existing violations non-blocking while you work through them.
Step 2: Add to GitHub Actions
# Add this step to your existing .github/workflows/ci.yml
- name: nark — dependency error handling
run: npx nark --tsconfig tsconfig.json
That's the complete addition. Full example workflow:
name: CI
on:
pull_request:
branches: [main]
jobs:
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
run: npx tsc --noEmit
- name: ESLint
run: npx eslint src --ext .ts,.tsx
- name: Tests
run: npx vitest run
# Add this:
- name: nark — dependency error handling
run: npx nark --tsconfig tsconfig.json
Common Configurations
Only fail CI on errors (not warnings)
Useful when introducing Nark to an existing codebase with accumulated issues. Errors block CI; warnings are reported but don't fail the build.
- name: nark
run: npx nark --tsconfig tsconfig.json --min-severity error
Monorepo with multiple packages
- name: nark — API
run: npx nark --tsconfig apps/api/tsconfig.json
- name: nark — Web
run: npx nark --tsconfig apps/web/tsconfig.json
Or using a matrix:
strategy:
matrix:
package: [apps/api, apps/web, packages/shared]
steps:
# ... checkout, setup, install ...
- name: nark — ${{ matrix.package }}
run: npx nark --tsconfig ${{ matrix.package }}/tsconfig.json
JSON output for downstream processing
- name: nark — generate report
run: npx nark --tsconfig tsconfig.json --format json > nark-report.json
continue-on-error: true
- name: Upload nark report
uses: actions/upload-artifact@v4
with:
name: nark-violations
path: nark-report.json
Run in parallel with other checks
jobs:
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: 'npm' }
- run: npm ci && npx tsc --noEmit
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: 'npm' }
- run: npm ci && npx eslint src --ext .ts,.tsx
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: 'npm' }
- run: npm ci && npx vitest run
nark:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: 'npm' }
- run: npm ci && npx nark --tsconfig tsconfig.json
Other CI Systems
CircleCI
# .circleci/config.yml
version: 2.1
jobs:
nark:
docker:
- image: node:20
steps:
- checkout
- run: npm ci
- run: npx nark --tsconfig tsconfig.json
workflows:
ci:
jobs:
- nark
GitLab CI
# .gitlab-ci.yml
nark:
image: node:20
script:
- npm ci
- npx nark --tsconfig tsconfig.json
Bitbucket Pipelines
# bitbucket-pipelines.yml
pipelines:
pull-requests:
'**':
- step:
name: nark — dependency error handling
image: node:20
script:
- npm ci
- npx nark --tsconfig tsconfig.json
Pre-commit hook (optional)
Run Nark before every commit locally:
# .husky/pre-commit
npx nark --tsconfig tsconfig.json --min-severity error
What Nark Checks
Nark has profiles for 160+ npm packages. The most common violations found in TypeScript SaaS projects:
| Package | What Nark catches |
|---|---|
axios | Missing try-catch, error.response null check on network errors |
@prisma/client | P2002 (unique constraint), P2025 (not found), connection errors |
stripe | StripeCardError (declined card), StripeRateLimitError, auth errors |
ioredis | Missing .on('error') handler (causes process crash) |
pg | Connection errors, query errors without client release |
@anthropic-ai/sdk | RateLimitError, APIConnectionError |
openai | RateLimitError, AuthenticationError |
nodemailer | SMTP errors, connection failures |
@sendgrid/mail | API errors, rate limits |
jsonwebtoken | TokenExpiredError, JsonWebTokenError |
Fixing Common Violations
axios without try-catch
// Before (nark violation)
const response = await axios.get('/api/users');
// After (nark passes)
try {
const response = await axios.get('/api/users');
return response.data;
} catch (error: unknown) {
if (axios.isAxiosError(error)) {
if (error.response) {
throw new ApiError(error.response.status);
}
throw new NetworkError(error.code ?? 'UNKNOWN');
}
throw error;
}
Prisma without P2002 handling
// Before (nark violation)
await prisma.user.create({ data: { email, password } });
// After (nark passes)
try {
return await prisma.user.create({ data: { email, password } });
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
if (error.code === 'P2002') {
throw new ConflictError('Email already in use');
}
}
throw error;
}
Redis without error handler
// Before (nark violation — crashes process on connection failure)
const redis = new Redis({ host: 'localhost', port: 6379 });
// After (nark passes)
const redis = new Redis({ host: 'localhost', port: 6379 });
redis.on('error', (error) => {
console.error('Redis connection error:', error);
});
Frequently Asked Questions
Does Nark require any configuration?
No. Nark reads your tsconfig.json and automatically discovers your TypeScript source files. It only reports on packages you actually import.
How long does Nark take to run?
15-30 seconds on a typical TypeScript project. Running it in parallel with Vitest keeps total CI time unchanged.
Will Nark have false positives?
Nark's profiles are binary checks based on documented package behavior. If a violation is reported, the specific postcondition it's checking is documented in the package's official materials. That said, if your codebase has framework-level error handling that Nark can't see (e.g., an Express error middleware), use --min-severity error or exclusion patterns.
Does Nark require a paid plan?
No. npx nark runs entirely locally. No signup, no API key, no data sent anywhere.
Try It Now
npx nark --tsconfig ./tsconfig.json
Then add to CI:
- name: nark — dependency error handling
run: npx nark --tsconfig tsconfig.json
Nark checks 160+ packages — including axios, prisma, stripe, and redis — for correct error handling. Two minutes to add, prevents the class of production crashes that TypeScript types and ESLint can't catch.