Chapter 64 โ€” Express vs NestJS

๐Ÿ“– Definitions

  • Express โ€” a minimalist, unopinionated Node.js web framework.
  • NestJS โ€” a TypeScript-first, opinionated framework built on top of Express (or optionally Fastify), inspired by Angular's architecture (modules, controllers, providers, decorators).

๐Ÿ” Comparison

Aspect Express NestJS
Style Minimalist Opinionated, modular
Language JS/TS (either) TypeScript-first
Architecture You design it Modules + DI built-in
DI Manual Built-in IoC container
Validation Manual (Joi, Zod) class-validator + DTOs
Boilerplate Low Higher (but consistent)
Testing Roll-your-own setup Built-in test utilities
Best for Small services, prototypes, niche apps Large enterprise apps, teams
Performance Fast, minimal overhead Slightly heavier (acceptable for most cases)

๐Ÿ’ป Code Example โ€” Same Endpoint in Both

Express

// app.js
import express from "express";
import { z } from "zod";

const app = express();
app.use(express.json());

const CreateUserSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
});

const users = [];

app.post("/users", (req, res) => {
  const parsed = CreateUserSchema.safeParse(req.body);
  if (!parsed.success) {
    return res.status(400).json({ errors: parsed.error.flatten() });
  }
  const user = { id: users.length + 1, ...parsed.data };
  users.push(user);
  res.status(201).json(user);
});

app.listen(3000);

NestJS

// user.dto.ts
import { IsEmail, MinLength } from "class-validator";

export class CreateUserDto {
  @IsEmail() email: string;
  @MinLength(8) password: string;
}

// user.controller.ts
@Controller("users")
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post()
  create(@Body() dto: CreateUserDto) {
    return this.userService.create(dto);
  }
}

// user.service.ts
@Injectable()
export class UserService {
  private users: any[] = [];
  create(dto: CreateUserDto) {
    const user = { id: this.users.length + 1, ...dto };
    this.users.push(user);
    return user;
  }
}

// user.module.ts
@Module({
  controllers: [UserController],
  providers:   [UserService],
})
export class UserModule {}

// main.ts
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
  await app.listen(3000);
}
bootstrap();

Same endpoint โ€” Nest is more code upfront, but scales much better as the app grows.

๐Ÿ’ป Code Example โ€” DI Difference

Express (Manual)

// You manually instantiate and wire dependencies
const db          = createDb();
const userRepo    = new UserRepository(db);
const userService = new UserService(userRepo);
const userCtrl    = new UserController(userService);

app.get("/users/:id", (req, res) => userCtrl.get(req, res));

NestJS (Automatic)

@Injectable()
export class UserService {
  constructor(private readonly userRepo: UserRepository) {}    // โ† injected automatically
}

// You declare in module, Nest handles the wiring:
@Module({
  providers: [UserService, UserRepository, DbProvider],
})
export class UserModule {}

๐Ÿ’ป Code Example โ€” Testing

// NestJS โ€” easy to swap dependencies
const module = await Test.createTestingModule({
  controllers: [UserController],
  providers: [
    UserService,
    { provide: UserRepository, useValue: mockRepo },     // โ† mock
  ],
}).compile();

const ctrl = module.get(UserController);
expect(await ctrl.get("1")).toEqual({ id: "1", name: "Mock" });

In Express you can do the same, but you build the harness yourself.

๐Ÿ“Š When to Choose Which

Scenario Pick
1โ€“2 endpoints, quick PoC Express
Lambdas / small workers Express / native handlers
Internal CLI / scripts Express / none
Large team, complex domain NestJS
Need OpenAPI, validation, DI out of the box NestJS
You want strict structure to onboard juniors quickly NestJS

๐ŸŽฏ Likely Interview Questions

  1. Difference between Express and NestJS?
  2. Why use NestJS over Express? โ€” Built-in DI, modules, validation, testing utilities, OpenAPI, guards/interceptors. Better for large codebases.
  3. What's NestJS inspired by? โ€” Angular (decorators, modules, providers).
  4. Can NestJS use Express under the hood? โ€” Yes, by default it uses Express. You can switch to Fastify for performance.

โ† Testing Node APIs | Index | Next: Dependency Injection โ†’