Node.js Framework

Express

Express es el framework web para Node.js minimalista y no opinado. Una ruta, una función y una cadena de middleware: ese es todo el modelo mental, y aun así impulsa una enorme parte de la web.

beginner16 min readUpdated 16 sept 2026
server.js
js
// server.js
import express from "express";

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

app.get("/users/:id", async (req, res, next) => {
  try {
    const user = await db.user.findById(req.params.id);
    if (!user) return res.status(404).json({ error: "not_found" });
    res.json(user);
  } catch (err) {
    next(err);
  }
});

app.listen(3000);
Lanzado
2010
Ejecuta sobre
Node.js
Estilo
Minimalista, no opinado
Idea central
Cadena de middleware
Lenguaje
JavaScript / TypeScript
Versión
5.x

Por que importa

Por qué Express sigue estando en todas partes

Enrutamiento sin ceremonias

Define endpoints con app.get, app.post y similares. Las rutas pueden ser estáticas, parametrizadas o basadas en patrones, y los manejadores siguen siendo funciones simples.

Middleware para todo

La autenticación, el logging, el parsing y la validación son simplemente funciones en una cadena. Compón piezas pequeñas en lugar de configurar un framework masivo.

Un ecosistema enorme

Miles de paquetes de middleware y años de respuestas significan que casi cualquier problema ya tiene una solución pequeña y bien probada.

La imagen completa

Las tres ideas detrás de Express

Una ruta coincide con una URL, un manejador recibe la solicitud y la respuesta, y el middleware envuelve todo lo que hay en medio.

Enrutamiento

Coincidir

Un método y una ruta seleccionan el manejador que se ejecuta. Las rutas pueden agruparse en routers y montarse bajo un prefijo.

Middleware

Componer

Las funciones reciben (req, res, next) y ya sea finalizan la respuesta o pasan el control hacia abajo en la cadena.

Solicitud y Respuesta

Intercambio

Envoltorios ligeros sobre los objetos HTTP de Node: lee la entrada, establece el estado y los encabezados, y envía un cuerpo.

HTML5 de un vistazo

Lo que realmente obtienes

Rutas

app.get("/posts/:id") coincide con una URL y ejecuta un manejador.

Middleware

app.use(fn) se ejecuta antes o después de las rutas, en el orden de registro.

req y res

Lee params, query y body; establece el estado y envía JSON o archivos.

Routers

express.Router() mantiene las aplicaciones grandes modulares y montables.

Middleware de errores

Una función de cuatro argumentos centraliza las respuestas de error.

Middleware de seguridad

helmet, cors y límites de tasa se implementan en una sola línea.

Una breve historia

De un juguete inspirado en Sinatra a un estándar web

  1. 2010

    Nace Express

    TJ Holowaychuk lanza un framework pequeño inspirado en Sinatra de Ruby.

    10
  2. 2011

    Middleware de Connect

    Express absorbe el modelo de middleware de Connect, que define su API durante años.

    11
  3. 2014

    Express 4

    El router es reescrito y el middleware se desvincula en paquetes separados.

    14
  4. 2016

    La era de la gobernanza abierta

    La gestión de IBM y StrongLoop mantiene Express actualizado mientras Node crece.

    16
  5. 2024

    Express 5

    Un lanzamiento mayor muy esperado trae el manejo de errores asíncronos y una base moderna.

    24

La guia completa

Express: Todo lo que necesitas saber

¿Qué es Express?

Express es un framework web minimalista para Node.js. No impone una estructura de carpetas, una base de datos ni una arquitectura específica. Simplemente te ofrece tres cosas y te deja trabajar: una forma de hacer match con URLs, un objeto de solicitud (request) y otro de respuesta (response), y una cadena de middleware que los conecta.

Esa simplicidad es precisamente su objetivo. Express llegó en 2010, cuando el módulo http integrado de Node requería que escribieras el enrutamiento y el parseo del cuerpo de las peticiones a mano. Express redujo esas tareas a unas pocas líneas. Quince años después, sigue siendo la opción predeterminada para APIs en Node, y sus conceptos han sido adoptados por casi todos los frameworks posteriores.

Si entiendes Express, entiendes la estructura de JavaScript en el lado del servidor.

El ciclo de solicitud y respuesta

En esencia, una aplicación de Express es una función que recibe una solicitud y envía una respuesta. Todo lo demás es una capa de conveniencia.

import express from "express";

const app = express();

app.get("/", (req, res) => {
  res.send("Hello, world");
});

El objeto req envuelve el mensaje entrante de Node: req.params, req.query, req.body y req.headers te proporcionan la entrada. El objeto res envuelve el mensaje saliente: res.status(), res.json(), res.send() y res.set() dan forma a la salida. Un handler finaliza la solicitud llamando a uno de los métodos res.

Enrutamiento

Una ruta es un método, una ruta (path) y uno o más manejadores (handlers). Las rutas pueden ser estáticas, parametrizadas con :name, o coincidir con patrones.

app.get("/posts", listPosts);
app.get("/posts/:id", getPost);
app.post("/posts", createPost);
app.put("/posts/:id", replacePost);
app.patch("/posts/:id", updatePost);
app.delete("/posts/:id", deletePost);

Los parámetros de la ruta llegan en req.params, y las query strings en req.query.

app.get("/posts/:id", (req, res) => {
  const { id } = req.params;          // "/posts/42" -> "42"
  const { fields } = req.query;       // "?fields=title" -> "title"
  res.json({ id, fields });
});

También puedes pasar varios manejadores a una sola ruta. Estos se ejecutan en orden hasta que uno finaliza la respuesta, que es la forma en que adjuntas middleware por ruta, como la validación o la autorización.

app.post("/posts", requireAuth, validatePost, createPost);

Middleware: el concepto fundamental que debes dominar

El middleware es el corazón de Express. Es cualquier función que recibe (req, res, next) y, o bien finaliza la respuesta, o llama a next() para continuar.

function logger(req, res, next) {
  const start = Date.now();
  res.on("finish", () => {
    console.log(`${req.method} ${req.url} ${res.statusCode} ${Date.now() - start}ms`);
  });
  next();
}

app.use(logger);

El middleware se ejecuta en el orden en que se registra. Esa única regla explica la mayor parte del comportamiento de Express: registra el parser de JSON antes de las rutas que lean req.body, registra la autenticación antes de las rutas protegidas y registra el manejador de errores 404 después de todas las rutas.

Hay tres tipos que vale la pena conocer:

  • Application middlewareapp.use(fn) se ejecuta en cada solicitud.
  • Router middlewarerouter.use(fn) se ejecuta solo para las rutas de ese router.
  • Route middlewareapp.get(path, fn, handler) se ejecuta solo para esa ruta.

Un middleware que recibe cuatro argumentos es un error handler y solo se ejecuta cuando algo llama a next(err).

Los routers mantienen la legibilidad en aplicaciones grandes

A medida que una aplicación crece, un único archivo de rutas se vuelve inmanejable. express.Router() te permite agrupar rutas relacionadas y montarlas bajo un prefijo.

// routes/posts.js
import { Router } from "express";

const router = Router();

router.get("/", listPosts);
router.post("/", createPost);

export default router;
// app.js
import posts from "./routes/posts.js";

app.use("/api/v1/posts", posts);

Ahora, cada archivo es dueño de un recurso y el prefijo de la URL reside en un solo lugar. Esta es la estructura que evita que los proyectos de Express se conviertan en un montón desordenado de endpoints.

Manejo de errores

Los errores deben fluir hacia un único lugar. Llama a next(err) desde cualquier parte y Express saltará directamente al primer manejador de errores de cuatro argumentos.

app.get("/users/:id", async (req, res, next) => {
  try {
    const user = await db.user.findById(req.params.id);
    if (!user) return res.status(404).json({ error: "not_found" });
    res.json(user);
  } catch (err) {
    next(err);
  }
});
app.use((err, req, res, next) => {
  console.error(err);
  res.status(err.status ?? 500).json({
    error: err.code ?? "internal_error",
    message: err.message,
  });
});

Express 5 reenvía las promesas rechazadas al manejador de errores automáticamente, por lo que los manejadores async ya no necesitan un wrapper. Aun así, ser explícito con try/catch hace que la intención sea obvia y mantiene el código portable. Registra un manejador 404 después de todas las rutas para que las rutas no coincidentes devuelvan un error JSON adecuado en lugar de la página HTML predeterminada de Express.

Lectura del cuerpo de la solicitud

Express no analiza los cuerpos de las solicitudes por defecto. Añade los parsers integrados antes de las rutas que los necesiten.

app.use(express.json());                        // application/json
app.use(express.urlencoded({ extended: true })); // form posts

Para la subida de archivos, utiliza multer. Para una validación más robusta, combina el parsing con una librería de esquemas como Zod o Joi y rechaza las entradas incorrectas lo antes posible, antes de que lleguen a tus handlers.

Conceptos básicos de seguridad y producción

Express es deliberadamente minimalista, por lo que unas pocas líneas de middleware cubren lo esencial:

import helmet from "helmet";
import cors from "cors";
import rateLimit from "express-rate-limit";

app.use(helmet());                 // sensible security headers
app.use(cors({ origin: "https://app.example.com" }));
app.use(rateLimit({ windowMs: 60_000, max: 100 }));

Además, desactiva x-powered-by, mantén las dependencias actualizadas, valida y limita el tamaño de las solicitudes, y nunca confíes en la entrada del cliente. Estas son las mismas preocupaciones que tiene cualquier backend; Express simplemente te ofrece un lugar pequeño y conocido para gestionar cada una de ellas.

Pruebas

Dado que los handlers son funciones simples, Express es fácil de testear. supertest arranca la aplicación en el mismo proceso y realiza aserciones HTTP reales sin necesidad de abrir un puerto.

import request from "supertest";
import app from "../app.js";

test("GET /posts returns a list", async () => {
  const res = await request(app).get("/posts").expect(200);
  expect(Array.isArray(res.body)).toBe(true);
});

Separa la definición de la aplicación (app.js) del inicio del servidor (server.js) para que los tests puedan importar la app sin ponerse a escuchar peticiones. Esa simple división hace que las pruebas de integración sean triviales.

Mejores prácticas

  • Mantén los route handlers ligeros; mueve la lógica a servicios y capas de acceso a datos.
  • Divide las rutas por funcionalidad con express.Router() y móntalas bajo un prefijo de versión.
  • Registra el middleware de forma deliberada y en orden: primero los parsers, luego la autenticación, luego las rutas, luego el 404 y finalmente los errores.
  • Redirige cada error con next(err) y formatea las respuestas en un solo lugar.
  • Valida y limita todas las entradas antes de que lleguen a la lógica de negocio.
  • Utiliza helmet, cors y rate limiting desde el primer día.
  • Separa la aplicación del servidor para que los tests sigan siendo rápidos.

Errores comunes

  • Olvidar express.json() y preguntarse por qué req.body es undefined.
  • Ignorar promesas rechazadas en handlers asíncronos en Express 4.
  • Registrar el handler de 404 o de errores antes de las rutas que debería capturar.
  • Dejar que un único archivo de rutas crezca hasta tener cientos de líneas.
  • Devolver un 200 para errores en lugar de utilizar códigos de estado.
  • Confiar en req.body sin realizar una validación.
  • Mezclar res.send, res.json y res.end de forma impredecible.

Próximos pasos

Express te enseña el request, el response y la cadena de middleware — conceptos que reutilizarás siempre. Si buscas más velocidad y validación integrada, lee a continuación la guía de Fastify. Si prefieres estructura e inyección de dependencias para un equipo grande, pasa a NestJS. Para despliegues en edge y serverless, Hono ofrece el mismo estilo sobre un runtime basado en estándares web. Y si sientes que todo esto fue muy rápido, repasa los conceptos básicos de Node.js que sustentan todo esto.

En la practica

Una app, cuatro piezas móviles

Cambia entre las piezas para ver cómo encajan.

server.js
import express from "express";
import routes from "./routes.js";

const app = express();

app.use(express.json());
app.use("/api", routes);

app.listen(3000, () => console.log("http://localhost:3000"));

Manejo de errores asíncronos

Express 5 reenvía automáticamente las promesas rechazadas, pero ser explícito sigue siendo más claro y funciona igual en cualquier versión.

Preferido
router.get("/posts", async (req, res, next) => {
  try {
    const posts = await Post.find();
    res.json(posts);
  } catch (err) {
    next(err);
  }
});
Evitar
router.get("/posts", async (req, res) => {
  const posts = await Post.find();
  res.json(posts);
  // rejection is silently lost in Express 4
});

Orden del middleware

El middleware se ejecuta en el orden de registro, por lo que el parser y la autenticación deben montarse antes que las rutas que dependen de ellos.

Preferido
app.use(express.json());
app.use(auth);
app.use("/api", routes);
app.use(notFound);
app.use(onError);
Evitar
app.use("/api", routes);
app.use(express.json());
app.use(auth);
// body is undefined inside routes

Compromisos

¿Es Express la opción predeterminada correcta?

Express optimiza la familiaridad y la simplicidad. Conoce el costo antes de escalarlo.

Strengths

  • Nada que aprender primero

    La API es diminuta, la documentación es excelente y casi cualquier desarrollador de Node puede leer una app de Express desde el primer día.

  • El ecosistema es inigualable

    Autenticación, subidas de archivos, sesiones, validación y logging tienen middleware maduro con años de uso en producción.

  • Tú mantienes el control

    No hay una estructura oculta. Tú eliges la organización de carpetas, la base de datos y los patrones en lugar de adoptar las opiniones de un framework.

Trade-offs

  • Tú construyes las convenciones

    Sin una estructura acordada, las apps grandes de Express tienden a tener manejadores inconsistentes. Un diseño claro importa más aquí que en frameworks opinados.

  • El rendimiento es bueno, no genial

    Express es lo suficientemente rápido para la mayoría de los servicios, pero Fastify y Node puro pueden manejar notablemente más solicitudes por segundo.

  • Los errores asíncronos son fáciles de omitir

    En Express 4, una promesa rechazada se descarta silenciosamente. Incluso en la versión 5, un try/catch o next(err) mantiene los fallos visibles.

Preguntas frecuentes

Preguntas frecuentes

Keep learning

Related topics from the roadmap.

$ comienza a aprender

Listo para aprender Express?

Nuestro tutorial interactivo te guia a traves de Express paso a paso — con quizzes y codigo real que puedes ejecutar en el navegador.