¡Ven a la JSConf España 2026! Comprar entradas

Creando nuestro primer servidor HTTP y usando watch

En esta clase damos el primer paso real en el desarrollo backend con Node.js: crear un servidor HTTP desde cero, sin frameworks y usando únicamente módulos nativos.

Entender cómo funciona la comunicación básica entre cliente y servidor es fundamental antes de pasar a herramientas de mayor nivel como Express.

El módulo nativo node:http

Node.js trae de serie todo lo necesario para montar un servidor. No necesitas instalar nada externo para empezar, ya que Node:

  • Tiene módulos nativos para comunicaciones.
  • Tiene acceso directo a la red.
  • Puede levantar servidores HTTP de forma eficiente.

Para empezar, usaremos el módulo node:http, que es la base de prácticamente todos los frameworks web en el ecosistema de Node.js.

Crear un servidor HTTP básico

Un servidor HTTP en Node.js se basa en un ciclo de petición (Request) y respuesta (Response).

Para crear uno, utilizamos el método createServer. Este método recibe una función (callback) que se ejecutará cada vez que el servidor reciba una petición.

import http from 'node:http'

const server = http.createServer((req, res) => {
  console.log('Petición recibida')
  res.end('Hola desde tu primer servidor de Node.js!')
})

Request y Response

La función que pasamos a createServer recibe dos objetos fundamentales:

  1. req (Request): Contiene toda la información de la petición que hace el cliente (la URL, el método HTTP, las cabeceras, etc.).
  2. res (Response): Es el objeto que usamos para enviarle la respuesta al cliente.

Escuchar en un puerto

Una vez definido el servidor, tenemos que decirle que “escuche” en un puerto específico de nuestra máquina para poder recibir tráfico.

const DESIRED_PORT = 3000

server.listen(DESIRED_PORT, () => {
  console.log(`Servidor escuchando en el puerto http://localhost:${DESIRED_PORT}`)
})

El ciclo de vida de la respuesta

Un error común al empezar es olvidar finalizar la respuesta. Si el servidor recibe la petición pero nunca llama a res.end(), el navegador se quedará cargando indefinidamente (en estado pending) esperando a que el servidor cierre la conexión.

Siempre debemos:

  1. Escribir el contenido (opcionalmente con res.write()).
  2. Finalizar la respuesta con res.end().

Cabeceras y Codificación (UTF-8)

Si intentas enviar caracteres especiales (como acentos o emojis) y no configuras correctamente el servidor, el navegador podría mostrarlos mal. Esto sucede porque el navegador no sabe qué tipo de contenido está recibiendo ni qué codificación usa.

Podemos solucionar esto enviando una cabecera HTTP:

const server = http.createServer((req, res) => {
  // Configuramos la cabecera con el código de estado 200 (OK)
  res.setHeader('Content-Type', 'text/plain; charset=utf-8')

  res.end('¡Hola Mundo! 🚀 Aquí tienes un servidor con tildes.')
})

Tip: Puedes inspeccionar estas cabeceras en las Herramientas de Desarrollo de tu navegador (F12), en la pestaña Network, seleccionando la petición a localhost.

Mejorando el desarrollo con el modo watch

Por defecto, cuando haces un cambio en tu archivo de Node.js, tienes que:

  1. Parar el proceso actual (Ctrl + C).
  2. Volver a ejecutar node servidor.js.

Esto es muy tedioso. Afortunadamente, las versiones recientes de Node.js (v18.11+) incluyen un modo watch nativo.

Para usarlo, simplemente añade el flag --watch:

node --watch servidor.js

Ahora, cada vez que guardes el archivo, Node.js reiniciará el servidor automáticamente. ¡Mucho más productivo!

Por qué empezar sin frameworks

Aunque en el mundo real usaremos Express, Fastify o NestJS, empezar con el módulo http nativo te permite entender:

  • Qué es realmente una petición.
  • Cómo funcionan los flujos de datos (streams).
  • La importancia de las cabeceras.
  • El ciclo de vida de una conexión.

Una vez dominas esto, verás que Express no es “magia”, sino una capa de utilidades sobre lo que acabas de aprender.

Resumen de la clase

  • ✅ Creamos un servidor con node:http.
  • ✅ Entendimos la diferencia entre req (petición) y res (respuesta).
  • ✅ Aprendimos a configurar el puerto con server.listen.
  • ✅ Vimos la importancia de las cabeceras para la codificación UTF-8.
  • ✅ Usamos el flag --watch para un desarrollo más rápido.

¡Ya tienes tu primer servidor funcionando! En la siguiente clase empezaremos a gestionar diferentes rutas.