You can build an entire application using only Node.js's core http module. Most people don't, and understanding why clarifies what a framework is actually for.
A library vs. a framework — the real difference
A library is something you call when you need it. A framework calls your code, on its terms, inside a structure it defines. That's the whole distinction, and it explains a lot: with a library, you're in the driver's seat; with a framework, you write pieces that fit into a shape someone else designed.
Watching the gap between raw Node.js and a framework
Handling a few routes with only core http:
const http = require('http');
http.createServer((req, res) => {
if (req.method === 'GET' && req.url === '/products') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify([{ id: 1, name: 'Notebook' }]));
} else if (req.method === 'POST' && req.url === '/products') {
// you'd need to manually read and parse the request body here
res.writeHead(201);
res.end('Created');
} else {
res.writeHead(404);
res.end('Not found');
}
}).listen(3000);
Even with just two routes, you're manually checking method and URL combinations, and parsing a POST body would take several more lines of raw stream-handling code. The same thing with Express:
const express = require('express');
const app = express();
app.use(express.json());
app.get('/products', (req, res) => {
res.json([{ id: 1, name: 'Notebook' }]);
});
app.post('/products', (req, res) => {
console.log(req.body); // already parsed for you
res.status(201).send('Created');
});
app.listen(3000);
Routing is declarative, the request body is parsed automatically, and adding a tenth route doesn't mean a tenth if/else if branch.
Types of frameworks you'll come across
- Backend/web frameworks (Express, NestJS, Fastify) — structure how a server handles routes, requests, and middleware.
- Frontend frameworks (React, Vue, Angular) — structure how a user interface is built and updated.
- Full-stack frameworks (Next.js) — combine both concerns into a single project structure.
What you give up in exchange for convenience
A framework's structure is a trade, not a free gift. You get speed, consistency, and a common vocabulary other developers already recognize — but you also inherit its opinions about how code should be organized, and swapping frameworks later usually means real rewrite work, not a drop-in replacement. For a two-route prototype, raw Node.js might genuinely be simpler. For anything with real routing, validation, and middleware needs, a framework tends to pay for itself quickly.