NestJS backend
Ness uses NestJS for public server routes while React Router handles the UI, loaders, actions, and SSR. Both frameworks run on the same HTTP server: Nest controllers are mounted first and unmatched requests continue to the React application.
Project structureβ
app/
βββ routes/ # React pages, layouts, loaders, actions
βββ server/ # NestJS backend
βββ app.module.ts
βββ users/
βββ users.controller.ts
βββ users.service.ts
βββ users.module.ts
New applications include @nessframework/nest, NestJS 11, reflect-metadata, and RxJS. NestJS 11 and Express 5 must be used together: @nestjs/platform-express@11 calls Express 5 APIs, and pairing it with Express 4 fails at application start.
app/server is TypeScript in every starter, including the JavaScript one. Nest is built on decorators, and decorators do not exist in JavaScript β writing this folder in JavaScript means applying every decorator by hand:
// What JavaScript forces you to write instead of @Get('health')
Get('health')(
ApiController.prototype,
'health',
Object.getOwnPropertyDescriptor(ApiController.prototype, 'health'),
);
The JavaScript starter therefore keeps app/server/tsconfig.json scoped to that folder rather than at the project root, so the React side stays JavaScript. Nothing else needs configuring: the Nest compiler transpiles app/server on its own, in development and in the build.
Root moduleβ
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module.js';
@Module({ imports: [UsersModule] })
export class AppModule {}
Use .js in relative TypeScript imports. The Nest compiler resolves the source .ts file and emits ESM files that Node can load directly.
Controller and serviceβ
import { Controller, Get } from '@nestjs/common';
import { UsersService } from './users.service.js';
@Controller('users')
export class UsersController {
constructor(private readonly users: UsersService) {}
@Get()
findAll() {
return this.users.findAll();
}
}
import { Injectable } from '@nestjs/common';
@Injectable()
export class UsersService {
findAll() {
return [];
}
}
All controllers receive the global /api prefix by default. Nest decorators for validation, guards, interceptors, exception filters, versioning, and OpenAPI can be used normally.
Generate backend modulesβ
ness g controller users
ness g service users
ness g module users
ness g guard users/auth
ness g resource products
The generator writes Nest modules under app/server and registers controllers, providers, guards, and imported modules in app/server/app.module.ts when it exists.
Development and productionβ
The @nessframework/nest Vite plugin compiles decorators with emitDecoratorMetadata, mounts the application during ness dev, and reloads it when app/server changes. ness build writes the ESM backend to build/nest.
The production bridge is configured in ness.config.mjs:
import { defineNessConfig } from '@nessframework/router';
import { nestServer } from '@nessframework/nest/server';
export default defineNessConfig({
server: { configureServer: nestServer({ prefix: 'api' }) },
});
The prefix must be non-empty so unknown URLs can continue to the React application. Change it to another namespace such as v1 when needed.