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-modulefor standard NestJS,nestjs-dddfor DDD-style,layeredfor generic layered architecture. - Data volumes: Set these to match your production table sizes. This enables volume-aware detection — an unbounded
findManyon an XXL table is critical, on an S table it's informational. - Mode: Start with
warnto see violations without blocking PRs. Switch toenforceonce 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:
- The action triggers — GitHub Actions runs the radar scan on the PR's code changes.
- Scan completes — Results appear in 5-15 seconds depending on project size.
- PR comment posted — A detailed comment appears on the PR showing all violations found, with file paths, line numbers, and fix suggestions.
- Status check set — A "Technical Debt Radar" check appears on the PR. If critical violations are found, the check fails.
- 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:
- 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. - Week 2: Fix critical issues — Address the critical and high violations from the baseline scan. There are usually only 3-5 of these.
- Week 3:
mode: enforcewithfail-on: critical— Now block merges on critical issues only. This catches new event loop blockers and severe runtime risks. - 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:
- Run
npx technical-debt-radar initto generate your config - Copy the GitHub Actions workflow into
.github/workflows/radar.yml - Add your
RADAR_TOKENto GitHub Secrets - 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.