Skip to main content

Node.js ๐ŸŸข

Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine, designed for building scalable network applications. Its event-driven, non-blocking I/O model makes it lightweight and efficient for data-intensive real-time applications.

Architectureโ€‹

JavaScript Code
โ†“
Node.js APIs (fs, http, path, crypto, ...)
โ†“
libuv (async I/O, event loop, thread pool)
โ†“
Operating System

Key characteristics:

FeatureDescription
Single-threaded event loopOne main thread handles all JS execution; I/O is offloaded to the kernel or thread pool
Non-blocking I/OOperations that would block use callbacks/promises, keeping the thread free for other requests
Event-drivenThe event loop picks up completed I/O operations and invokes their callbacks
Cross-platformRuns on Linux, macOS, Windows, and more

Core Modulesโ€‹

ModulePurpose
fsFile system operations
http / httpsHTTP server and client
pathFile path utilities
cryptoCryptographic functions
streamStreaming data processing
eventsEventEmitter base class
child_processSpawn subprocesses
worker_threadsTrue multi-threading for CPU-bound tasks
clusterMulti-process load balancing
osOperating system utilities
urlURL parsing and formatting

Express ๐Ÿš‚โ€‹

Express is the most popular Node.js web framework โ€” minimal, unopinionated, and battle-tested. It provides a thin layer of fundamental web application features on top of Node.js.

Core Conceptsโ€‹

Middleware pipeline:

const express = require('express');
const app = express();

// Application-level middleware
app.use(express.json()); // parse JSON bodies
app.use(express.urlencoded({ extended: true })); // parse form data
app.use((req, res, next) => {
// custom logger
console.log(`${req.method} ${req.url}`);
next();
});

// Route-level middleware
app.get('/api/users', authenticate, getUsers);

Routing:

// Basic routes
app.get('/api/users', getUsers);
app.post('/api/users', createUser);
app.put('/api/users/:id', updateUser);
app.delete('/api/users/:id', deleteUser);

// Router modules (modular organization)
const userRouter = express.Router();
userRouter.get('/', getUsers);
userRouter.get('/:id', getUserById);
app.use('/api/users', userRouter);

Error handling middleware (4 parameters):

app.use((err, req, res, next) => {
console.error(err.stack);
res.status(err.status || 500).json({
error: { message: err.message },
});
});

Project Structureโ€‹

src/
โ”œโ”€โ”€ routes/ # Route definitions
โ”‚ โ”œโ”€โ”€ users.js
โ”‚ โ””โ”€โ”€ products.js
โ”œโ”€โ”€ controllers/ # Request handlers
โ”‚ โ”œโ”€โ”€ userController.js
โ”‚ โ””โ”€โ”€ productController.js
โ”œโ”€โ”€ middleware/ # Custom middleware
โ”‚ โ”œโ”€โ”€ auth.js
โ”‚ โ”œโ”€โ”€ validation.js
โ”‚ โ””โ”€โ”€ errorHandler.js
โ”œโ”€โ”€ models/ # Database models
โ”œโ”€โ”€ services/ # Business logic
โ”œโ”€โ”€ utils/ # Helper functions
โ”œโ”€โ”€ config/ # Configuration
โ””โ”€โ”€ app.js # Entry point

NestJS ๐Ÿฑโ€‹

NestJS is a progressive framework for building efficient, scalable server-side applications. It uses TypeScript by default and combines elements of OOP, FP, and FRP (Functional Reactive Programming).

Core Conceptsโ€‹

Modules โ€” organize application structure:

@Module({
imports: [UsersModule, AuthModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

Controllers โ€” handle incoming requests:

@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}

@Get()
findAll(): Promise<User[]> {
return this.usersService.findAll();
}

@Get(':id')
findOne(@Param('id') id: string): Promise<User> {
return this.usersService.findOne(id);
}

@Post()
create(@Body() createUserDto: CreateUserDto): Promise<User> {
return this.usersService.create(createUserDto);
}
}

Providers / Services โ€” business logic, injectable via DI:

@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>,
) {}

async findAll(): Promise<User[]> {
return this.userRepository.find();
}
}

Guards โ€” authorization (roles, permissions):

@Injectable()
export class RolesGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const roles = this.reflector.get<string[]>('roles', context.getHandler());
const request = context.switchToHttp().getRequest();
return roles.includes(request.user?.role);
}
}

@UseGuards(RolesGuard)
@Roles('admin')
@Get('admin')
getAdminData() {}

Interceptors โ€” transform responses, wrap logic:

@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(map((data) => ({ success: true, data, timestamp: new Date() })));
}
}

Pipes โ€” validate and transform input:

@Post()
create(@Body(new ValidationPipe()) createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}

NestJS CLIโ€‹

# Generate a full CRUD resource
nest g resource users

# Generate individual components
nest g module auth
nest g controller auth
nest g service auth
nest g guard roles
nest g pipe validation

Express vs NestJSโ€‹

CriteriaExpressNestJS
PhilosophyMinimal, unopinionatedOpinionated, batteries-included
ArchitectureMiddleware functionsModules, controllers, providers
TypeScriptOptional, manual setupFirst-class, built-in
Dependency InjectionManual, not built-inBuilt-in DI container
TestingManual setup (Jest, Mocha)Built-in testing module with Jest
GraphQLManual setupBuilt-in code-first and schema-first
MicroservicesManualBuilt-in transport layer (Redis, NATS, MQTT)
Best forSmall to medium apps, APIsLarge enterprise apps, complex architectures

โ† Back to Backend Engineering ยท ยฉ sparshjaswal