Configuration

Project Configuration (radar.yml)

Complete reference for radar.yml — the project configuration file that tells Technical Debt Radar about your stack, architecture, modules, and data volumes.

Project Configuration: radar.yml

The radar.yml file lives at the root of your repository and describes what your project is. It declares your tech stack, architectural layers, module boundaries, and data volume expectations. The policy engine reads this file on every scan to understand your codebase structure before analyzing it.

# radar.yml — minimum viable configuration
stack:
  language: TypeScript
  framework: NestJS
  orm: Prisma

layers:
  - name: api
    path: "src/**/controllers/**"
  - name: domain
    path: "src/**/domain/**"

modules:
  - name: billing
    path: "src/billing/**"

Tip: Run radar init to auto-detect your stack and generate both radar.yml and rules.yml with sensible defaults.


Configuration Modes

Technical Debt Radar supports two configuration modes:

ModeFilesWhen to use
Two-file (recommended)radar.yml + rules.ymlProduction projects. Project config and enforcement rules live separately.
Single-file (legacy)radar.yml onlyQuick prototypes. All config including rules, gates, and exceptions in one file.

In two-file mode, radar.yml declares what your project is while rules.yml declares what to enforce. When both files exist, rules.yml takes precedence for all enforcement-related fields.


Full Schema Reference

stack (required)

Declares your technology stack. The policy engine uses this to select the right analyzers and apply framework-specific detection rules.

stack:
  language: TypeScript
  framework: NestJS
  orm: Prisma
  build_tool: Nx
  structure: modular-monolith
  runtime: node
FieldTypeRequiredDescription
languagestringYesOne of: TypeScript, JavaScript, Java, Python, Go
frameworkstringYesFramework name: NestJS, Express, Fastify, Next.js, Spring, etc.
ormstringYesORM/ODM name: Prisma, TypeORM, Sequelize, Mongoose, Drizzle, MikroORM
build_toolstringNoBuild tool: Nx, Turborepo, Lerna, Rush, etc.
structurestringNoOne of: monolith, modular-monolith, microservices
runtimestringNoOne of: node, jvm, python, go

Note: The orm field drives volume auto-detection. Technical Debt Radar parses Prisma schemas, TypeORM entities, Sequelize models, Mongoose schemas, Drizzle table definitions, and MikroORM entities to estimate data volumes automatically.


architecture (optional)

Declares which architecture preset(s) to use for rule generation. When set, radar init generates architecture-specific rules in rules.yml.

# Single preset
architecture: ddd

# Multiple presets (combined rules)
architecture: [ddd, event-driven]
TypeValues
string or string[]ddd, hexagonal, clean, layered, mvc, event-driven, feature-module

When using multiple presets, rules from all presets are merged and deduplicated. If the same dependency path has both a deny and an allow rule, the deny rule wins (security-first).

See Architecture Presets for full details on each preset.

Warning: Some preset combinations are unusual and may generate conflicting rules. The following combinations are flagged: ddd + mvc, hexagonal + mvc, clean + mvc, clean + layered.


layers (required)

Defines the architectural layers in your project using glob patterns. Layer names are referenced in dependency rules.

layers:
  - name: api
    path: "src/**/controllers/**"
  - name: application
    path: "src/**/use-cases/**"
  - name: domain
    path: "src/**/domain/**"
  - name: infrastructure
    path: "src/**/infra/**"
FieldTypeRequiredDescription
namestringYesUnique identifier for the layer. Referenced in rules.
pathstringYesGlob pattern matching files in this layer.

Layer names must be unique. Glob patterns support standard syntax: * (any file), ** (any directory depth), ? (single char), {a,b} (alternatives).

How layers work: When analyzing a file, the policy engine matches its path against each layer's glob pattern. A file at src/billing/controllers/invoice.controller.ts matches the api layer pattern src/**/controllers/**. Dependency rules then govern which layers can import from which.


modules (required)

Defines bounded modules in your codebase. Modules represent feature areas or domains that should maintain clear boundaries.

modules:
  - name: billing
    path: "src/billing/**"
  - name: identity
    path: "src/identity/**"
  - name: orders
    path: "src/orders/**"
FieldTypeRequiredDescription
namestringYesUnique identifier for the module.
pathstringYesGlob pattern matching files in this module.

Module names must be unique and cannot overlap with layer names. Cross-module dependency rules (like deny: cross-module direct imports) use these definitions to detect boundary violations.


data_volumes (optional in two-file mode)

Maps database entities to expected row count tiers. This drives volume-aware severity scaling for performance rules.

data_volumes:
  orders: L
  events: XL
  users: M
  companies: S
  measurements: XXL
SizeRow estimateEffect on performance rules
S< 10KMost performance warnings suppressed
M10K -- 100KWarnings shown
L100K -- 1MSeverity elevated to Critical
XL1M -- 50MBlocks merge
XXL> 50MBlocks merge

Tip: If you skip data_volumes, run radar init to auto-detect volumes from your ORM schema. The estimator uses entity naming patterns (e.g., Event* defaults to XL, Config* defaults to S) and relation counts to produce reasonable defaults.

See Volume Configuration for detailed volume behavior.


rules (optional in two-file mode)

Dependency rules that govern allowed and forbidden imports between layers and modules. In two-file mode, define these in rules.yml under architecture_rules instead.

rules:
  # Shorthand syntax
  - deny: domain -> infrastructure
  - deny: domain -> api
  - deny: api -> infrastructure
  - deny: cross-module direct imports
  - allow: cross-module through "src/**/contracts/**"

  # Structured syntax
  - type: deny
    source: domain
    target: infrastructure
    description: "Domain must not depend on infrastructure"

Two syntaxes are supported:

Shorthand syntax:

  • deny: source -> target -- forbids imports from source layer/module into target
  • allow: source -> target -- permits imports (overrides a deny)
  • deny: source <- target -- reverse direction (target cannot import from source)
  • deny: cross-module direct imports -- forbids all cross-module imports
  • allow: cross-module through "glob" -- permits cross-module imports through specific paths

Structured syntax:

FieldTypeRequiredDescription
typestringYesallow or deny
sourcestringYesSource layer/module name, or cross-module
targetstringYesTarget layer/module name, or cross-module
throughstringNoGlob pattern for allowed import path
descriptionstringNoHuman-readable description

The special target __db__ represents direct database/ORM package imports (e.g., importing @prisma/client directly).


runtime_rules (optional)

Controls which Node.js runtime safety patterns are blocked or warned about.

runtime_rules:
  block:
    - sync-fs-in-handler
    - sync-crypto
    - sync-compression
    - redos-vulnerable-regex
    - busy-wait-loop
    - unhandled-promise
  warn:
    - unbounded-json-parse
    - large-json-stringify
    - cpu-heavy-loop-in-handler
    - unbounded-array-operation
    - dynamic-buffer-alloc

Available runtime rules:

RuleDescriptionDefault
sync-fs-in-handlerSynchronous fs.*Sync() calls in request handlersBlock
sync-cryptoSynchronous crypto.pbkdf2Sync(), scryptSync(), etc.Block
sync-compressionSynchronous zlib.*Sync() callsBlock
redos-vulnerable-regexRegular expressions vulnerable to ReDoS attacksBlock
busy-wait-loopwhile(true) or busy-wait spin loopsBlock
unhandled-promisePromise without .catch() or await in try/catchBlock
unbounded-json-parseJSON.parse() on untrusted input without size limitsWarn
large-json-stringifyJSON.stringify() on potentially large objectsWarn
cpu-heavy-loop-in-handlerCPU-intensive loops inside request handlersWarn
unbounded-array-operation.map(), .filter(), .reduce() on unbounded arraysWarn
dynamic-buffer-allocBuffer.alloc() with dynamic/untrusted sizeWarn

reliability_rules (optional)

Controls which reliability patterns are blocked or warned about.

reliability_rules:
  block:
    - unhandled-promise-rejection
  warn:
    - missing-try-catch
    - external-call-no-timeout
    - retry-without-backoff
    - empty-catch-block
    - missing-error-logging
    - transaction-no-timeout
    - missing-null-guard

Available reliability rules:

RuleDescriptionDefault
unhandled-promise-rejectionPromises that can reject without a handlerBlock
missing-try-catchAsync operations without error handlingWarn
external-call-no-timeoutHTTP/gRPC calls without timeout configurationWarn
retry-without-backoffRetry logic without exponential backoffWarn
empty-catch-blockcatch blocks that swallow errors silentlyWarn
missing-error-loggingError paths without loggingWarn
transaction-no-timeoutDatabase transactions without timeoutWarn
missing-null-guardNullable values accessed without null checksWarn

gates (optional in two-file mode)

Merge gate conditions that determine whether a PR is blocked or warned.

gates:
  block_merge:
    - architecture_violations > 0
    - circular_dependencies_introduced > 0
    - runtime_risk_critical > 0
    - reliability_critical > 0
    - critical_performance_risk > 0
    - debt_delta_score > 15
  warn:
    - complexity_increase > 5
    - coverage_drop > 2%
    - debt_delta_score > 8

Each condition follows the format metric operator value. Supported operators: >, >=, <, <=, ==.

Available gate metrics:

MetricDescription
architecture_violationsCount of layer/module boundary violations
circular_dependencies_introducedNew circular dependency chains detected
runtime_risk_criticalCount of critical runtime risk findings
reliability_criticalCount of critical reliability findings
critical_performance_riskCount of critical performance findings
debt_delta_scoreNet change in technical debt score
complexity_increaseCyclomatic complexity increase
coverage_dropTest coverage percentage decrease
maintainability_violationsCount of maintainability issues
runtime_risk_warningCount of warning-level runtime risks
reliability_warningCount of warning-level reliability issues

exceptions (optional)

Temporary exemptions for specific rules on specific files. Every exception requires an expiration date and a reason.

exceptions:
  - rule: "domain -> infrastructure"
    file: "src/billing/domain/legacy-adapter.ts"
    expires: "2026-06-01"
    reason: "Legacy migration — tracked in JIRA-1234"
FieldTypeRequiredDescription
rulestringYesThe rule being exempted (e.g., domain -> infrastructure)
filestringYesFile path the exception applies to
expiresstringYesExpiration date in YYYY-MM-DD format
reasonstringYesReason for the exception (include ticket reference)

Expired exceptions are automatically ignored. The dashboard shows upcoming expirations.

Warning: Exceptions without an expires date will fail validation. This is intentional -- every exception must be temporary.


standards (optional)

Declarative coding standards that the AI analysis engine evaluates against. These are natural-language descriptions of your team's conventions.

standards:
  error_handling:
    - all use-cases must have try/catch with typed errors
    - no swallowed exceptions
  logging:
    - all controllers must log request entry/exit
    - no console.log in production code
  naming:
    - "use-cases: <Verb><Noun>UseCase"
    - "repositories: <Entity>Repository"
  transactions:
    - Prisma transactions only in infrastructure layer
  dto_mapping:
    - no Prisma types in application or domain layer

Standards are free-form string arrays grouped by category. The AI engine uses them as context when analyzing the top 10 suspect functions in a PR.


scoring (optional)

Override default scoring weights for debt calculation. Each finding type adds or subtracts from the debt delta score.

scoring:
  architecture_violation: 5
  circular_dependency: 10
  runtime_risk_critical: 8
  runtime_risk_warning: 3
  performance_risk_critical: 8
  performance_risk_warning: 3
  reliability_critical: 5
  reliability_warning: 3

All scoring keys and defaults:

KeyDefaultDescription
architecture_violation5Points per layer/module boundary violation
circular_dependency10Points per circular dependency chain
runtime_risk_critical8Points per critical runtime risk
runtime_risk_warning3Points per warning-level runtime risk
performance_risk_critical8Points per critical performance risk
performance_risk_warning3Points per warning-level performance risk
reliability_critical5Points per critical reliability issue
reliability_warning3Points per warning-level reliability issue
complexity_point1Points per unit of complexity increase
missing_tests3Points per file without tests
coverage_drop_per_pct2Points per percentage of coverage drop
ai_concern2Points per AI-identified concern
violation_fixed-5Credit for fixing a violation
runtime_risk_fixed-8Credit for fixing a runtime risk
complexity_reduced-1Credit per unit of complexity reduced
reliability_fixed-3Credit for fixing a reliability issue

Negative values are credits -- they reduce the debt delta score when a PR fixes existing issues.


Complete Examples

NestJS + Prisma + DDD

stack:
  language: TypeScript
  framework: NestJS
  orm: Prisma
  build_tool: Nx
  structure: modular-monolith
  runtime: node

architecture: ddd

layers:
  - name: api
    path: "src/**/controllers/**"
  - name: application
    path: "src/**/use-cases/**"
  - name: domain
    path: "src/**/domain/**"
  - name: infrastructure
    path: "src/**/infra/**"

modules:
  - name: billing
    path: "src/billing/**"
  - name: identity
    path: "src/identity/**"
  - name: orders
    path: "src/orders/**"

data_volumes:
  orders: L
  events: XL
  users: M
  measurements: XXL

Express + Sequelize + Layered

stack:
  language: TypeScript
  framework: Express
  orm: Sequelize
  runtime: node

architecture: layered

layers:
  - name: routes
    path: "src/routes/**"
  - name: controllers
    path: "src/controllers/**"
  - name: services
    path: "src/services/**"
  - name: repositories
    path: "src/repositories/**"
  - name: models
    path: "src/models/**"

modules:
  - name: core
    path: "src/**"

data_volumes:
  users: M
  orders: L
  products: M

Fastify + Prisma + Clean Architecture

stack:
  language: TypeScript
  framework: Fastify
  orm: Prisma
  runtime: node

architecture: clean

layers:
  - name: domain
    path: "src/domain/**"
  - name: use-cases
    path: "src/use-cases/**"
  - name: adapters
    path: "src/adapters/**"
  - name: infrastructure
    path: "src/infrastructure/**"
  - name: routes
    path: "src/routes/**"

modules:
  - name: core
    path: "src/**"

data_volumes:
  orders: L
  users: M

Validation

Run the validator to check your configuration before committing:

radar validate

The validator checks:

  • YAML syntax is valid
  • All required fields are present
  • stack.language, stack.structure, and stack.runtime values are from allowed sets
  • Layer and module paths are valid glob patterns
  • No duplicate layer or module names
  • Rule sources/targets reference defined layers or modules
  • Scoring keys are recognized
  • Exception dates are in YYYY-MM-DD format

File Resolution

Technical Debt Radar looks for configuration files in this order:

  1. radar.yml in the repository root
  2. .radar/radar.yml in the repository root
  3. Path specified via --config CLI flag

For rules:

  1. rules.yml in the same directory as radar.yml
  2. .radar/rules.yml in the repository root
  3. Path specified via --rules CLI flag
  4. Falls back to rules embedded in radar.yml (single-file mode)
Technical Debt Radar Documentation