NestJS brings structure to Node.js backends through decorators, modules, and dependency injection. But that structure creates its own class of hidden defects – circular dependencies, decorator ordering mistakes, leaking providers, and module boundaries that erode over time. VibeRails scans your entire NestJS application and finds the architectural decay that linters cannot detect.
NestJS provides an opinionated module system inspired by Angular. In the early stages of a project, modules are small, providers are focused, and the dependency graph is clean. As the application grows, that clarity degrades in predictable ways. Modules begin importing each other to share services, creating circular dependency chains that NestJS resolves with forwardRef() rather than surfacing the underlying architectural problem. Each forwardRef is a band-aid over a module boundary violation that will make future refactoring more difficult.
Decorator-based programming introduces a different kind of opacity. A controller method decorated with @UseGuards(), @UseInterceptors(), and @UsePipes() has behaviour that depends entirely on the order and combination of those decorators. The execution pipeline – guards first, then interceptors, then pipes – is well-defined in the NestJS documentation, but in practice developers stack decorators without reasoning about their interaction. A guard that checks authentication runs before an interceptor that logs requests, but a pipe that validates the request body runs after both. When these layers conflict or duplicate logic, the result is subtle bugs that only manifest under specific request conditions.
Provider scope is another area where NestJS projects silently accumulate risk. The default singleton scope works well for stateless services, but request-scoped providers introduce performance overhead and change how the dependency injection container resolves the entire provider chain. A single request-scoped provider forces every provider that depends on it to also become request-scoped, cascading through the dependency graph in ways that are not visible from any individual file.
Repository patterns add further complexity. Teams using TypeORM or Prisma with NestJS often start with clean repository abstractions but gradually bypass them – injecting the ORM directly into services, mixing query builder calls with repository methods, or scattering raw SQL across multiple modules. The inconsistency makes it difficult to reason about data access patterns and introduces risks around transaction management, connection pooling, and query optimisation.
ESLint can enforce coding style. The NestJS CLI can generate modules, controllers, and services with consistent boilerplate. TypeScript catches type-level errors at compile time. But none of these tools can evaluate the architectural health of a NestJS application as a whole.
Consider a service that injects six other services. TypeScript confirms that all injection tokens resolve. ESLint sees no rule violations. But the service has become a God object – a single class responsible for orchestrating user management, notification dispatch, payment processing, and audit logging. The issue is structural, not syntactic, and no linter rule will flag it.
Circular dependencies between modules are technically resolvable with forwardRef(), so the NestJS runtime does not throw an error. But the presence of forward references signals that module boundaries are wrong. A codebase with a dozen forward references has a dependency graph that no developer can reason about without tooling. Existing linters do not track cross-module dependency chains or flag circular patterns as architectural risks.
Guard and interceptor ordering is another blind spot. When multiple guards are applied to a controller, their execution order depends on the order of the decorator arguments. Swap two guards and you change the security behaviour of every endpoint on that controller. No linter checks whether the authentication guard runs before the authorisation guard, or whether a rate-limiting interceptor is applied consistently across all public-facing controllers.
Custom decorators compound the problem further. Teams create parameter decorators, method decorators, and class decorators that encapsulate framework behaviour. When these custom decorators interact with NestJS lifecycle hooks, pipes, or exception filters, the resulting behaviour is determined by composition rules that exist only in the framework internals. A decorator that extracts the current user from the request works correctly in isolation but fails silently when combined with a guard that has not yet populated the user property.
VibeRails performs a full-codebase scan using frontier large language models. Every module, controller, service, guard, interceptor, pipe, and configuration file is analysed alongside test files and infrastructure code. The AI reads each file and reasons about its role within the NestJS module system, its dependency relationships, and its interaction with the request lifecycle.
For NestJS codebases specifically, the review covers:
forwardRef() to resolve, and service dependency graphs that form cycles indicating misplaced module boundariesEach finding includes the file path, line range, severity, category, and a detailed description explaining the architectural implication and how to address it.
The most valuable findings in a NestJS review are the ones that span multiple modules. A circular dependency involves at least two modules and often three or four. A guard ordering issue requires understanding which guards are applied at the controller level, which at the method level, and which globally. An inconsistent repository pattern is only visible when you compare how different feature modules access the same database entities.
VibeRails supports running reviews with two different AI backends – Claude Code and Codex CLI – in sequence. The first pass discovers issues; the second pass verifies them using a different model architecture. This dual-model approach is particularly valuable for NestJS because many architectural concerns are judgement calls. A module with fifteen providers might be well-structured if those providers are cohesive. A forward reference might be acceptable in a specific bootstrapping scenario. Cross-validation helps distinguish genuine architectural decay from acceptable pragmatic choices.
The structured output organises findings into 17 categories so teams can focus on what matters most. Filter by dependency injection issues to clean up the module graph. Filter by security to ensure guards and authentication are applied consistently. Filter by performance to find N+1 queries hiding behind repository abstractions.
After triaging findings, VibeRails can dispatch AI agents to implement fixes directly in your local repository. For NestJS projects, this typically means extracting shared services into dedicated modules, replacing forwardRef() usage with properly structured module boundaries, consolidating guard and interceptor application patterns, and standardising repository access across feature modules.
Each fix is generated as a local code change you can inspect, test, and commit or discard. The AI works within the conventions of your existing codebase – matching your module naming patterns, provider registration style, and testing approach.
VibeRails runs as a desktop app with a BYOK model – it orchestrates Claude Code or Codex CLI installations you already have. No code is uploaded to VibeRails servers. Source code is sent directly to the AI provider you configured, billed to your existing subscription. Per-developer pricing: $19/month or $299 lifetime, with a free tier of 5 issues per session to evaluate the workflow.
Cuéntanos sobre tu equipo y objetivos. Te responderemos con un plan concreto de despliegue.