After this lesson, you will be able to: Build HTTP servers: raw http module → Express → Fastify.
Each layer adds productivity. Knowing all three makes you fluent across legacy + modern codebases.
Useful for low-level tasks; rarely used directly.
import { createServer } from "node:http";const server = createServer((req, res) => {res.writeHead(200, { "Content-Type": "application/json" });res.end(JSON.stringify({ url: req.url, method: req.method }));});server.listen(3000, () => console.log("on :3000"));
Still the default. Mature; huge ecosystem.
import express from "express";import { z } from "zod";const app = express();app.use(express.json());app.get("/users", async (req, res) => {const users = await db.user.findMany();res.json(users);});const CreateUser = z.object({ name: z.string(), email: z.string().email() });app.post("/users", async (req, res) => {const parsed = CreateUser.safeParse(req.body);if (!parsed.success) return res.status(400).json({ error: parsed.error.flatten() });const user = await db.user.create({ data: parsed.data });res.status(201).json(user);});app.listen(3000);
Built-in schema validation. Worth choosing for new projects.
import Fastify from "fastify";import { z } from "zod";const app = Fastify({ logger: true });app.get("/users", async () => db.user.findMany());const CreateUser = z.object({ name: z.string(), email: z.string().email() });app.post("/users", async (req, reply) => {const parsed = CreateUser.safeParse(req.body);if (!parsed.success) {reply.code(400);return { error: parsed.error.flatten() };}const user = await db.user.create({ data: parsed.data });reply.code(201);return user;});await app.listen({ port: 3000 });
Raw http: rare; for protocols below HTTP or extremely minimal services. Express: legacy default. Pick when joining an Express team. Fastify: new project default. Faster, schema-validated by design, better TS story. Hono: edge runtime + ultrafast; production-credible for Vercel / Cloudflare / Bun.
Pick the senior answer.
Sign in and purchase access to unlock this lesson.