The problem
In every TypeScript codebase I've worked on, the same violation appears eventually:
// controllers/orderController.ts
import { OrderRepository } from '../repositories/orderRepository'; // ❌
A controller importing a repository directly. The service layer completely bypassed.
ESLint can't catch this — it has no concept of architectural layers. Code reviews catch it sometimes, but not always. And the bugs it causes are subtle.
So I built architecture-linter.
How it works
You create a .context.yml in your project root:
architecture:
layers:
- controller
- service
- repository
rules:
controller:
cannot_import:
- repository
Then run:
npx architecture-linter scan
Output:
❌ Architecture violation detected
File: controllers/orderController.ts
Import: repositories/orderRepository
Rule: Controller cannot import Repository
Found 1 violation in 3 file(s) scanned.
Setup takes 2 minutes
npm install --save-dev architecture-linter
npx architecture-linter init # detects your layers automatically
npx architecture-linter scan
Three ways to use it
1. CLI — run locally or in any CI pipeline
2. VS Code extension — violations appear as red squiggles in real time, with fix hints in the Problems panel
3. GitHub Action — annotates PRs with inline violations on the exact line
- uses: cvalingam/architecture-linter@v0.1.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
Built-in presets
No need to write rules from scratch. Use a preset:
extends: nestjs # or clean-architecture, hexagonal
Available presets: nestjs, clean-architecture, hexagonal, nextjs, express
Links
- GitHub: https://github.com/cvalingam/architecture-linter
- npm: https://www.npmjs.com/package/architecture-linter
- VS Code Extension: https://marketplace.visualstudio.com/items?itemName=cvalingam.architecture-linter-vscode
Free and open source. Feedback welcome in the comments.
Top comments (0)