1. Introduction 🌐
Node.js was built from the start with networking in mind — its non-blocking I/O model makes it especially well suited for servers handling many concurrent connections. This tutorial covers the core networking modules: http, net, dns, tls, and more.
2. Networking in Node.js 🔌
Node exposes networking at multiple layers: low-level TCP/UDP sockets via net and dgram, encrypted connections via tls, and the familiar HTTP/HTTPS protocols built on top of them.
3. HTTP Module 📡
The http module (node:http) provides everything needed to create HTTP servers and clients without any external dependencies.
http-import.js
const http = require('node:http');4. HTTPS Module 🔒
https mirrors the http API, adding TLS encryption. It requires a certificate and private key.
https-server.js
const https = require('node:https');
const fs = require('node:fs');
const options = {
key: fs.readFileSync('./key.pem'),
cert: fs.readFileSync('./cert.pem'),
};
https.createServer(options, (req, res) => {
res.end('Secure response');
}).listen(443);5. Creating an HTTP Server 🖥️
basic-server.js
const http = require('node:http');
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello, World!\n');
});
server.listen(3000, () => {
console.log('Server running on port 3000');
});6. Handling Requests 📥
The req object is a Readable stream carrying the request method, URL, headers, and body.
handling-requests.js
const http = require('node:http');
http.createServer((req, res) => {
console.log(req.method, req.url);
let body = '';
req.on('data', (chunk) => (body += chunk));
req.on('end', () => {
console.log('Body:', body);
res.end('Received');
});
}).listen(3000);7. Sending Responses 📤
sending-responses.js
const http = require('node:http');
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.write(JSON.stringify({ message: 'ok' }));
res.end();
}).listen(3000);8. Request Headers 📋
request-headers.js
http.createServer((req, res) => {
console.log(req.headers['content-type']);
console.log(req.headers['user-agent']);
res.end();
}).listen(3000);9. Response Headers 📋
response-headers.js
http.createServer((req, res) => {
res.setHeader('X-Powered-By', 'Node.js');
res.setHeader('Content-Type', 'text/html');
res.end('<h1>Hello</h1>');
}).listen(3000);10. Status Codes 🚦
| Code | Meaning |
|---|---|
| 200 | OK |
| 201 | Created |
| 301 / 302 | Redirect (permanent / temporary) |
| 400 | Bad Request |
| 401 / 403 | Unauthorized / Forbidden |
| 404 | Not Found |
| 500 | Internal Server Error |
11. URL Handling 🔗
11.1 URL Module
The URL class (global, backed by node:url) parses a URL string into its component parts.
url-module.js
const myUrl = new URL('https://example.com:8080/path?name=node#section');
console.log(myUrl.hostname); // 'example.com'
console.log(myUrl.pathname); // '/path'
console.log(myUrl.port); // '8080'11.2 URL Parsing
url-parsing.js
const http = require('node:http');
http.createServer((req, res) => {
const myUrl = new URL(req.url, `http://${req.headers.host}`);
console.log(myUrl.pathname);
res.end();
}).listen(3000);11.3 Query Strings
query-strings.js
const myUrl = new URL('https://example.com/search?q=node&limit=10');
console.log(myUrl.searchParams.get('q')); // 'node'
console.log(myUrl.searchParams.get('limit')); // '10'12. DNS Module 🧭
The dns module resolves domain names to IP addresses and vice versa.
dns-module.js
const dns = require('node:dns/promises');
const addresses = await dns.resolve4('example.com');
console.log(addresses);
const { address } = await dns.lookup('example.com');
console.log(address);Information
13. Net Module (TCP) 🔌
13.1 TCP Servers
tcp-server.js
const net = require('node:net');
const server = net.createServer((socket) => {
console.log('Client connected');
socket.on('data', (data) => {
console.log('Received:', data.toString());
socket.write('Echo: ' + data);
});
socket.on('end', () => console.log('Client disconnected'));
});
server.listen(4000, () => console.log('TCP server on port 4000'));13.2 TCP Clients
tcp-client.js
const net = require('node:net');
const client = net.createConnection({ port: 4000 }, () => {
console.log('Connected to server');
client.write('Hello from client');
});
client.on('data', (data) => {
console.log('Server says:', data.toString());
client.end();
});14. UDP Module (Datagrams) 📮
dgram provides UDP sockets — connectionless, unordered, and lightweight, suited for real-time applications like video streaming or gaming where occasional packet loss is acceptable.
udp-server.js
const dgram = require('node:dgram');
const server = dgram.createSocket('udp4');
server.on('message', (msg, rinfo) => {
console.log(`Received: ${msg} from ${rinfo.address}:${rinfo.port}`);
});
server.bind(5000);15. TLS Module 🔐
tls provides encrypted socket communication built directly on top of net, implementing TLS/SSL. It underpins https.
tls-server.js
const tls = require('node:tls');
const fs = require('node:fs');
const options = {
key: fs.readFileSync('./key.pem'),
cert: fs.readFileSync('./cert.pem'),
};
tls.createServer(options, (socket) => {
socket.write('Encrypted hello\n');
socket.end();
}).listen(6000);16. HTTP Keep-Alive ♻️
Keep-Alive reuses a single TCP connection for multiple HTTP requests, avoiding the overhead of a new handshake per request.
keep-alive.js
const http = require('node:http');
const agent = new http.Agent({ keepAlive: true, maxSockets: 50 });
http.get('http://example.com', { agent }, (res) => {
res.resume();
});17. Compression 🗜️
Combining zlib with HTTP headers lets servers send gzip- or brotli-compressed responses, reducing bandwidth.
http-compression.js
const http = require('node:http');
const zlib = require('node:zlib');
const fs = require('node:fs');
http.createServer((req, res) => {
res.setHeader('Content-Encoding', 'gzip');
fs.createReadStream('./large.html').pipe(zlib.createGzip()).pipe(res);
}).listen(3000);18. CORS Basics 🌍
CORS headers tell browsers which origins are permitted to access a resource from a different domain than the one serving the page.
cors-basics.js
http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', 'https://myapp.com');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.end('OK');
}).listen(3000);Caution
19. Proxy Servers 🔀
A proxy server sits between a client and the destination server, forwarding requests on the client's behalf — often used for caching, filtering, or anonymization.
simple-proxy.js
const http = require('node:http');
http.createServer((clientReq, clientRes) => {
const proxyReq = http.request(
{ hostname: 'example.com', port: 80, path: clientReq.url, method: clientReq.method, headers: clientReq.headers },
(proxyRes) => {
clientRes.writeHead(proxyRes.statusCode, proxyRes.headers);
proxyRes.pipe(clientRes);
}
);
clientReq.pipe(proxyReq);
}).listen(8080);20. Reverse Proxies 🔁
A reverse proxy sits in front of one or more backend servers, routing incoming requests to the appropriate service — commonly used for load balancing, TLS termination, and routing by path or subdomain.
Reference
21. Performance Optimization ⚡
- Enable Keep-Alive agents for outbound requests to reduce connection overhead.
- Compress responses with gzip or brotli for text-heavy payloads.
- Use streaming (.pipe()) instead of buffering entire request/response bodies.
- Scale across CPU cores using the cluster module or a process manager.
22. Best Practices ✅
- Always set explicit timeouts on servers and clients to avoid hanging connections.
- Validate and sanitize all incoming URL and header values.
- Use https/tls for anything handling sensitive data.
- Prefer a well-tested framework (like Express or Fastify) over hand-rolled routing for production apps.
23. Common Mistakes ⚠️
- Forgetting to call res.end(), leaving requests hanging indefinitely.
- Not handling the 'error' event on sockets and servers.
- Setting Access-Control-Allow-Origin: * on endpoints returning sensitive data.
- Buffering entire large request bodies into memory instead of streaming them.
- Not reusing connections (missing Keep-Alive) when making many outbound requests.