Skip to content

CruzJS vs NestJS

CruzJS and NestJS share a love for dependency injection and modular architecture, but they solve different problems. NestJS is a mature, backend-only framework. CruzJS is a full-stack application framework that deploys to Cloudflare Workers/Pages by default, with first-class support for AWS, GCP, Azure, DigitalOcean, and Docker via runtime adapters.

NestJS is the most popular enterprise Node.js framework. It brings Angular-style DI, decorators, and modules to the backend, supporting REST, GraphQL, WebSockets, and microservices. It runs on Express or Fastify and deploys to any Node.js environment.

CruzJS is a full-stack TypeScript framework built on React Router v7. It deploys to Cloudflare Workers/Pages by default, with first-class support for AWS, GCP, Azure, DigitalOcean, and Docker via runtime adapters. It uses Inversify-based DI with a flat container model, tRPC for type-safe APIs, and includes auth, org management, and a React frontend out of the box.

AspectNestJSCruzJS
ScopeBackend onlyFull-stack (frontend + backend)
DI systemCustom DI with imports/exportsInversify with flat container
API layerREST, GraphQL, WebSockets, gRPCtRPC (type-safe RPC)
FrontendNone (bring your own)React Router v7 (SSR)
DatabaseTypeORM, Prisma, MikroORM, etc.Drizzle ORM — D1 on Cloudflare, PostgreSQL/MySQL/Aurora on AWS, GCP, Azure, DigitalOcean, Docker
AuthPassport.js (assemble yourself)Built-in (email/password, 7 OAuth providers, 2FA, magic links, API keys, RBAC)
RuntimeNode.js (Express/Fastify)Cloudflare Workers/Pages (default), AWS Lambda/Fargate, GCP Cloud Run/Functions, Azure Functions/Container Apps, DigitalOcean App Platform, Docker/K8s via runtime adapters
Deploy targetAny Node.js hostMulti-cloud via runtime adapters (Cloudflare, AWS, GCP, Azure, DigitalOcean, Docker)
Org/team managementNot includedBuilt-in with RBAC and invitations
CLInest generate scaffoldingcruz dev/deploy/db/new (full lifecycle)
Maturity7+ years, massive ecosystemNew framework, growing ecosystem

Both frameworks use modules to organize code, but the mechanics differ significantly.

NestJS modules explicitly declare imports, exports, providers, and controllers. Services must be exported to be available to other modules:

// NestJS
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService], // Must export for other modules
})
export class UsersModule {}
@Module({
imports: [UsersModule], // Must import to use UsersService
controllers: [OrdersController],
providers: [OrdersService],
})
export class OrdersModule {}

CruzJS uses a @Module decorator with a flat DI container — all services registered in any module are available everywhere. No import/export ceremony:

// CruzJS
@Module({
providers: [UsersService],
trpcRouters: { users: usersRouter },
})
export class UsersModule {}
@Module({
providers: [OrdersService], // Can inject UsersService directly
trpcRouters: { orders: ordersRouter },
})
export class OrdersModule {}

This is simpler but means you lose the encapsulation boundaries NestJS provides. Whether that’s a trade-off you want depends on your team size and project complexity.

@Controller('users')
export class UsersController {
constructor(private usersService: UsersService) {}
@Get(':id')
async findOne(@Param('id') id: string) {
return this.usersService.findOne(id);
}
@Post()
@UseGuards(AuthGuard)
async create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
}
export const usersRouter = router({
getById: protectedProcedure
.input(z.object({ id: z.string() }))
.query(({ input, ctx }) => {
return ctx.container.get(UsersService).findOne(input.id);
}),
create: protectedProcedure
.input(createUserSchema)
.mutation(({ input, ctx }) => {
return ctx.container.get(UsersService).create(input);
}),
});

With tRPC, the client gets full type inference — no code generation, no OpenAPI specs. With NestJS, you get REST conventions, Swagger docs, and broader client compatibility.

  • Maturity and stability. NestJS has been in production at thousands of companies for years. It is battle-tested at scale.
  • Ecosystem. Hundreds of official and community modules — rate limiting, caching, scheduling, health checks, CQRS, and more.
  • API flexibility. REST, GraphQL, WebSockets, gRPC, and microservice transports. CruzJS only offers tRPC out of the box.
  • Platform portability. Deploy to AWS, GCP, Azure, any VPS, Docker, Kubernetes — anywhere Node.js runs. CruzJS supports Cloudflare, AWS, GCP, Azure, DigitalOcean, and Docker via runtime adapters, but its ecosystem is still maturing compared to NestJS’s universal Node.js compatibility.
  • Encapsulation. NestJS’s import/export system enforces module boundaries, which matters for large teams.
  • Hiring. Many developers know NestJS. Finding CruzJS developers means training them.
  • Backend complexity. For complex backend-only systems (microservices, message queues, CQRS), NestJS has more patterns and tooling.
  • Full-stack in one framework. Frontend (React), backend (services + tRPC), database (Drizzle), auth, and org management — all integrated.
  • No assembly required. NestJS gives you DI and decorators; you still need to choose and wire up an ORM, auth library, frontend framework, and deployment strategy. CruzJS makes those choices for you.
  • Edge deployment. CruzJS deploys globally to Cloudflare’s edge network by default, with multi-cloud support via runtime adapters. Cold starts are measured in milliseconds, not seconds.
  • Simpler DI. @Module decorator with a flat container — no imports/exports ceremony. Register a service, inject it anywhere.
  • Type-safe API layer. tRPC gives you end-to-end type safety from database to UI with zero code generation.
  • Built-in auth and orgs. Social auth (7 OAuth providers: GitHub, Google, Discord, Twitter, LinkedIn, Microsoft, Apple), two-factor auth (TOTP + backup codes), magic links (passwordless), API keys, RBAC, team management, and member invitations are included — not bolted on.
  • CRUD Factory. createCrud() factory and BaseCrudService eliminate boilerplate for standard data operations.
  • Real-time. BroadcastModule provides SSE and presence out of the box.
  • Single CLI. cruz dev, cruz deploy, cruz db migrate — one tool for the full development lifecycle.
  • You are building a backend-only service or API (no frontend needed).
  • You need REST APIs, GraphQL, or WebSocket support.
  • You are deploying to AWS, GCP, or traditional servers.
  • You need the safety of a mature, widely-adopted framework.
  • Your team already knows NestJS.
  • You are building microservices that communicate via message queues or gRPC.
  • You need fine-grained module encapsulation for a large team.
  • You are building a full-stack SaaS application.
  • You want auth, orgs, RBAC, and database patterns out of the box.
  • You want to deploy to Cloudflare’s edge with minimal infrastructure management.
  • You prefer tRPC’s end-to-end type safety over REST or GraphQL.
  • You want a single framework that handles frontend and backend together.
  • You value convention over configuration and are comfortable with opinionated defaults.
  • Your project is greenfield and you want to move fast with integrated tooling.

NestJS is the safer, more established choice. It has years of production use, a massive community, and flexibility to handle almost any backend architecture. If you are building something that needs to last and you want a large hiring pool, NestJS is hard to argue against.

CruzJS is for teams that want the DI and structure of NestJS but don’t want to spend weeks assembling auth, a frontend, an ORM, and deployment infrastructure. It trades NestJS’s flexibility and ecosystem size for an integrated, full-stack experience that deploys to Cloudflare, AWS, GCP, Azure, DigitalOcean, or Docker. If you are building a SaaS product, CruzJS gets you to a working application faster — but you are betting on a younger framework with a smaller community.