Blog/Setting Up PR Quality Gates for Node.js in 5 Minutes
Tutorial

Setting Up PR Quality Gates for Node.js in 5 Minutes

5 min read

Every team has a story about the PR that broke production. The code looked fine, the tests passed, the reviewer approved it. But it contained a blocking readFileSync in a request handler, or an N+1 query on a table with 2 million rows, or a controller that bypassed the service layer entirely.

PR quality gates prevent this. They automatically scan every pull request for dangerous patterns and block the merge until the issues are fixed. Here's how to set one up in 5 minutes.

What You'll Get

By the end of this tutorial, every pull request in your repo will be automatically scanned for:

  • Architecture violations — controllers bypassing services, cross-module imports, layer boundary breaks
  • Runtime risks — synchronous I/O in handlers, blocking crypto, event loop killers
  • Performance anti-patterns — N+1 queries, unbounded findMany, fetch-all-filter-in-memory
  • Reliability issues — fire-and-forget promises, HTTP calls without timeouts, empty catch blocks

The scan takes seconds, runs in GitHub Actions, and posts results directly on the PR. Critical violations block the merge. Warnings are informational.

Step 1: Install and Run Your First Scan

Start by scanning your project locally to see what it finds:

# No install needed — npx runs it directly
npx technical-debt-radar scan .

# You'll see output like:
#   TECHNICAL DEBT RADAR — Local Scan
#
#   Scanning... done (6.2s)
#
#   Runtime Risk        3 issues (1 critical)
#   Performance         2 issues (1 high)
#   Architecture        1 issue  (medium)
#   Reliability         2 issues (low)
#
#   Total: 8 issues | Debt Score: 34/100
#   Status: FAIL (1 critical issue found)

Then initialize a config file:

# Generate a radar.yml tailored to your project
npx technical-debt-radar init

# This auto-detects:
# - Your framework (NestJS, Express, Fastify)
# - Your ORM (Prisma, TypeORM, Sequelize)
# - Your architecture style (layered, feature-module, DDD)
# - Your existing patterns and conventions

The init command creates a radar.yml file in your project root. This is your quality gate configuration.

Step 2: Review Your Config

Open the generated radar.yml and review the key sections:

# radar.yml — generated by `radar init`
project:
  name: my-api
  framework: nestjs
  orm: prisma

architecture:
  preset: nestjs-feature-module
  rules:
    - deny: controllers -> repositories
    - deny: domain -> infrastructure

analysis:
  runtime_risk:
    enabled: true
    severity: critical    # blocks merge on critical issues
  performance:
    enabled: true
    severity: high        # blocks merge on high+ issues
  architecture:
    enabled: true
    severity: medium      # blocks merge on medium+ issues
  reliability:
    enabled: true
    severity: low         # warns but doesn't block

data_volumes:
  users: L               # 100K-1M rows
  orders: XL             # 1M-10M rows
  events: XXL            # 10M+ rows

mode: warn               # start with warn, switch to enforce later

Key things to check:

  • Architecture preset: Make sure it matches your actual architecture. nestjs-feature-module for standard NestJS, nestjs-ddd for DDD-style, layered for generic layered architecture.
  • Data volumes: Set these to match your production table sizes. This enables volume-aware detection — an unbounded findMany on an XXL table is critical, on an S table it's informational.
  • Mode: Start with warn to see violations without blocking PRs. Switch to enforce once your team is comfortable.

Step 3: Add the GitHub Action

Create a workflow file at .github/workflows/radar.yml:

name: Technical Debt Radar
on:
  pull_request:
    branches: [main, develop]

jobs:
  radar-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: technical-debt-radar/action@v1
        with:
          fail-on: critical
          radar-token: ${{ secrets.RADAR_TOKEN }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

That's it. Four lines in the job step. Here's what each parameter does:

  • fail-on: critical — The action sets a failing status check when critical issues are found. Options: critical, high, medium, low, never.
  • radar-token — Your project token from the Technical Debt Radar dashboard. Free tier includes unlimited scans.
  • GITHUB_TOKEN — Allows the action to post scan results as a PR comment and set status checks.

Commit this file to your repo, and the next pull request will trigger the scan automatically.

Step 4: Your First Gated PR

When a developer opens a pull request, here's what happens:

  1. The action triggers — GitHub Actions runs the radar scan on the PR's code changes.
  2. Scan completes — Results appear in 5-15 seconds depending on project size.
  3. PR comment posted — A detailed comment appears on the PR showing all violations found, with file paths, line numbers, and fix suggestions.
  4. Status check set — A "Technical Debt Radar" check appears on the PR. If critical violations are found, the check fails.
  5. Merge blocked or allowed — If your branch protection rules require the radar check to pass, the merge button is disabled until violations are fixed.

The PR comment looks like this:

## Technical Debt Radar — Scan Results

### 1 Critical Issue Found

| Severity | Category | File | Description |
|----------|----------|------|-------------|
| CRITICAL | Runtime Risk | src/api/users.controller.ts:42 | readFileSync in request handler |
| HIGH | Performance | src/orders/orders.service.ts:18 | N+1 query on XL table (orders) |
| MEDIUM | Architecture | src/payments/payments.controller.ts:5 | Controller imports repository directly |

### Fix Suggestions
- **users.controller.ts:42** — Replace `fs.readFileSync` with `await fs.promises.readFile`
- **orders.service.ts:18** — Use `include` to eager-load relations instead of loop query
- **payments.controller.ts:5** — Inject PaymentsService instead of PaymentsRepository

Run `npx technical-debt-radar scan . --format ai-prompt` locally to get AI-ready fix suggestions.

Optional: Add AI-Powered Analysis

For deeper analysis, you can enable AI review that uses Claude to analyze your top violations and provide detailed fix suggestions. Create a separate workflow or add to the existing one:

# .github/workflows/radar-with-ai.yml
name: Technical Debt Radar (AI Review)
on:
  pull_request:
    branches: [main]

jobs:
  radar-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: technical-debt-radar/action@v1
        with:
          fail-on: critical
          with-ai: true
          ai-model: claude-sonnet
          radar-token: ${{ secrets.RADAR_TOKEN }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

The with-ai: true flag sends your top 10 most severe violations to Claude for analysis. The AI provides:

  • Detailed explanation of why each violation is dangerous
  • Concrete code fix suggestions tailored to your codebase
  • Impact assessment for production workloads

AI review adds 10-20 seconds to the scan but provides significantly more actionable feedback.

Start With Warn, Then Enforce

If your codebase has existing violations (most do), don't start with mode: enforce. That would block every PR until all existing issues are fixed.

Instead, follow this rollout plan:

  1. Week 1: mode: warn — The scan runs and posts comments, but never blocks the merge. This lets your team see what Radar catches without disrupting their workflow.
  2. Week 2: Fix critical issues — Address the critical and high violations from the baseline scan. There are usually only 3-5 of these.
  3. Week 3: mode: enforce with fail-on: critical — Now block merges on critical issues only. This catches new event loop blockers and severe runtime risks.
  4. Week 5: fail-on: high — Expand blocking to include high-severity issues like N+1 queries on large tables and architecture violations.

Update your radar.yml as you progress:

# Week 1: observe
mode: warn

# Week 3: enforce critical
mode: enforce
fail_on: critical

# Week 5: enforce high
mode: enforce
fail_on: high

This gradual rollout prevents the "wall of violations" problem and gives your team time to adopt the tool naturally.

Set Up Your Quality Gate Now

The entire setup takes 5 minutes:

  1. Run npx technical-debt-radar init to generate your config
  2. Copy the GitHub Actions workflow into .github/workflows/radar.yml
  3. Add your RADAR_TOKEN to GitHub Secrets
  4. Open a pull request and watch the scan run

Start with your first scan:

npx technical-debt-radar scan .

First scan is free, no account needed. See what's hiding in your PRs before it reaches production.

Detect these patterns automatically

Run one command. Get a full report in 10 seconds. No account needed.

npx technical-debt-radar scan .

Create a free account for unlimited scans and PR merge blocking.

Share:TwitterLinkedIn

Get Node.js architecture insights

No spam, unsubscribe anytime.