React 19 ya no manda todo tu código al navegador. Desde que los React Server Components llegaron a estable, una parte entera de tu aplicación puede vivir solo en el servidor y nunca empaquetarse en el JavaScript que descarga el usuario. Eso rompe una regla que llevaba más de una década fija en el desarrollo frontend, la de que todo componente de React corre, tarde o temprano, en el navegador.
La pieza que lo permite son los React Server Components: piezas de interfaz que se ejecutan exclusivamente en el servidor, leen datos directamente y jamás llegan al bundle del cliente. No sustituyen a React, lo dividen en dos entornos con una frontera explícita entre lo que corre en el servidor y lo que corre en el navegador.
TL;DR
- Un React Server Component corre solo en el servidor y nunca entra al bundle JavaScript del navegador.- La directiva 'use client' marca el límite exacto donde empieza el código que sí llega al navegador.- Next.js activó los componentes de servidor por defecto en el App Router desde la versión 13.4 (2023).- Guardar datos con una Server Action no exige escribir una sola línea de API REST.- El RSC Payload serializa el árbol del servidor y lo transmite en streaming al navegador.
¿Qué es React Server Components?
React Server Components son un tipo de componente de React que se ejecuta exclusivamente en el servidor durante el renderizado, sin incluir su código en el paquete JavaScript que descarga el navegador. No tienen acceso a hooks de estado ni a eventos del navegador: su trabajo es leer datos y producir interfaz.
La idea de renderizar en el servidor no es nueva (el PHP de los 2000 ya lo hacía), pero React la resuelve distinto: el servidor y el navegador comparten el mismo árbol de componentes, y un componente puede delegarle a otro, marcado con 'use client', la parte que necesita interactividad. El resultado es una sola aplicación con dos entornos de ejecución, no dos aplicaciones separadas comunicadas por una API REST clásica.
Por qué importan los componentes de servidor
El motivo práctico es el peso del bundle. Antes de RSC, para mostrar una lista que viene de una base de datos, React obligaba a enviar al navegador el código del componente, el código para pedir los datos (fetch, manejo de errores, estados de carga) y después ejecutar todo eso en el dispositivo del usuario. Con un componente de servidor, ese código entero se queda del lado del servidor: el navegador solo recibe el resultado ya renderizado.
Eso importa doblemente en dispositivos de gama baja o con redes lentas, donde el costo real no es solo descargar el JavaScript sino parsearlo y ejecutarlo antes de que la página responda a un clic. Un componente que nunca llega al navegador no carga ese costo, sin importar cuánta lógica tenga adentro.
También cambia la seguridad de los datos. Un componente de servidor puede importar un cliente de base de datos o una clave de API directamente, porque ese código jamás se serializa hacia el cliente. Antes, exponer esa misma lógica sin un backend intermedio hubiera filtrado la clave dentro del bundle.
Y cambia la experiencia del desarrollador: ya no hace falta levantar una ruta de API solo para que un componente pueda leer datos. El componente de servidor llama directamente a su fuente de datos, y ese viaje de red nunca sale del servidor.
Cómo funciona RSC por dentro
Cuando el navegador pide una página, el servidor arranca el árbol de componentes desde la raíz. Cada componente sin la directiva 'use client' es, por defecto, un componente de servidor: React lo ejecuta ahí mismo, resuelve sus await y produce una representación serializada llamada RSC Payload, que todavía no es HTML. Esa representación incluye el marcado de los componentes de servidor y referencias a los módulos de los componentes de cliente que encuentra en el camino.
El framework (en la práctica, casi siempre Next.js) toma ese payload y genera el HTML inicial para la primera carga, junto con el JavaScript mínimo necesario para hidratar solo los componentes de cliente. La hidratación ya no cubre toda la página: React ignora los componentes de servidor porque no tienen estado que reactivar, y solo conecta los event listeners de los componentes marcados con 'use client'.
Para navegaciones posteriores dentro de la misma sesión, el navegador no vuelve a pedir HTML completo: pide directamente el RSC Payload actualizado, lo aplica sobre el árbol que ya tiene en memoria y actualiza solo lo que cambió, sin perder el estado de los componentes de cliente que no se tocaron.
React 19 llegó a estable el 5 de diciembre de 2024, consolidando RSC fuera de fase experimental.
flowchart TD
A["Navegador solicita la pagina"] --> B["Servidor Next.js"]
B --> C["Componente de servidor"]
C --> D["fetch a una fuente de datos"]
D --> C
C --> E["RSC Payload serializado"]
E --> F["HTML inicial + referencias a componentes de cliente"]
F --> A
Ejemplos prácticos
El ejemplo más simple es un componente que lee datos y los muestra, sin ningún estado. No necesita la directiva 'use client' porque no usa ningún hook:
// app/posts/page.js
export default async function PostsPage() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=3');
const posts = await res.json();
return (
{posts.map((post) => (
- {post.title}
))}
);
}
Este componente corre en el servidor en cada request, pide los datos y el navegador recibe directamente el HTML con la lista ya armada. La salida en el código fuente de la página (clic derecho, ver código fuente) es literalmente esta:
- sunt aut facere repellat provident occaecati excepturi optio reprehenderit
- qui est esse
- ea molestias quasi exercitationem repellat qui ipsa sit aut
Ahora sumemos interactividad. Un botón de "me gusta" necesita estado, y el estado solo existe en componentes de cliente, por eso lleva la directiva al inicio del archivo:
// app/posts/LikeButton.js
'use client';
import { useState } from 'react';
export default function LikeButton() {
const [likes, setLikes] = useState(0);
return (
setLikes(likes + 1)}>
Me gusta ({likes})
);
}
Al cargar la página, ese botón se renderiza inicialmente como <button>Me gusta (0)</button>. Cada clic suma uno en el navegador, sin volver a tocar el servidor, porque ese estado vive solo ahí.
El caso real combina ambos: un componente de servidor que renderiza la lista y, dentro, importa el botón de cliente para cada item. React permite esa mezcla porque un componente de servidor puede importar y renderizar componentes de cliente (lo inverso, un componente de cliente importando uno de servidor, no está permitido).
El último escalón son las Server Actions: funciones marcadas con 'use server' que un formulario puede invocar directamente, sin que el desarrollador escriba una ruta de API:
// app/actions.js
'use server';
export async function addComment(formData) {
const text = formData.get('comment');
await db.comment.create({ data: { text } });
}
// app/posts/CommentForm.js
import { addComment } from '../actions';
export default function CommentForm() {
return (
Comentar
);
}
Al enviar el formulario, React serializa los datos, llama a addComment en el servidor y vuelve a renderizar el árbol afectado. No hay fetch manual ni endpoint que mantener: la función del servidor y el formulario del cliente quedan conectados por esa referencia.
sequenceDiagram
participant U as Usuario
participant N as Navegador
participant S as Servidor
U->>N: envia el formulario
N->>S: invoca addComment con los datos
S->>S: ejecuta addComment y guarda el comentario
S-->>N: devuelve el arbol actualizado
N-->>U: la UI se actualiza sin recargar
Cómo empezar
Para probar RSC de verdad hace falta un framework que los implemente: React por sí solo no trae un servidor. La vía más directa hoy es Next.js, que usa componentes de servidor por defecto en el App Router desde la versión 13.4. Antes de arrancar, se necesita Node.js 18.18 o superior (comprobalo con node -v).
npx create-next-app@latest rsc-demo
El instalador hace varias preguntas en la terminal: TypeScript (podés responder No para seguir los ejemplos de este artículo), ESLint (Yes), Tailwind CSS (No), usar una carpeta src/ (No), y si querés usar el App Router (hay que responder Yes, es el que trae RSC). Al terminar, entrá a la carpeta y levantá el servidor de desarrollo:
cd rsc-demo
npm run dev
La terminal muestra algo como - Local: http://localhost:3000. Abrí esa URL y vas a ver la página de bienvenida por defecto de Next.js, servida por un árbol de componentes de servidor.
Para confirmar que efectivamente estás usando RSC y no solo SSR tradicional, abrí las herramientas de desarrollo del navegador, pestaña Network, recargá la página y abrí la respuesta HTML cruda (clic derecho, ver código fuente). El contenido va a estar ya presente en el HTML, sin placeholders vacíos. Después, en la misma pestaña Network, abrí los archivos .js que descarga la página y buscá el nombre de un componente de servidor que hayas escrito: no debería aparecer en ningún bundle, porque ese código nunca salió del servidor.
💡 Tip: si necesitás confirmar en qué entorno corre un archivo puntual, importá
'server-only'(un paquete publicado por el propio equipo de Next.js) al principio del archivo: si alguien lo importa por error desde un componente de cliente, el build falla en vez de filtrar el código silenciosamente.
Casos de uso reales
Un dashboard que lee directamente de una base de datos interna sin pasar por una API pública es el caso más citado: el componente de servidor hace la consulta SQL o llama al ORM, y el navegador recibe solo la tabla ya armada. Ninguna credencial de la base de datos llega jamás al cliente.
Un blog o un sitio de documentación, donde el contenido cambia poco pero debe indexarse bien en buscadores, se beneficia de recibir HTML completo desde la primera respuesta sin pagar el costo de hidratar cada párrafo. Los elementos interactivos (un buscador, un botón de copiar código) quedan aislados en componentes de cliente puntuales.
Un formulario de checkout con validaciones que necesitan tocar un sistema de pagos es un buen candidato para Server Actions: la lógica sensible (verificar un cupón, cobrar una tarjeta) corre en el servidor sin exponer ninguna clave, y el formulario sigue sintiéndose instantáneo porque React maneja la transición sin recargar la página.
Un panel administrativo con tablas que se actualizan seguido también se beneficia: cada fila puede ser un componente de servidor que vuelve a pedir datos frescos en cada navegación interna, mientras los controles de filtro y orden quedan en un componente de cliente aparte que no necesita volver a tocar el servidor en cada tecla.
Errores comunes y buenas prácticas
El error más frecuente es usar un hook de estado dentro de un componente que no lleva 'use client'. Next.js lo detecta al compilar y corta el build con un mensaje similar a: Error: useState only works in a Client Component. La solución es mover ese fragmento puntual a su propio archivo con la directiva, en vez de marcar todo el árbol como cliente.
Marcar 'use client' demasiado arriba en el árbol es otro error típico: si el layout raíz lleva la directiva, todo lo que cuelga de él se vuelve componente de cliente, y se pierde el beneficio entero de RSC. La práctica recomendada es empujar la frontera lo más abajo posible, idealmente al componente puntual que necesita el hook o el evento, no al contenedor que lo rodea.
Pasar una función común como prop desde un componente de servidor a uno de cliente también falla, porque React no puede serializar una función arbitraria a través de esa frontera. Las únicas funciones que cruzan son las Server Actions marcadas con 'use server', que React sabe convertir en una referencia que el cliente puede invocar.
Importar por accidente una librería pensada para Node.js (que usa fs o variables de entorno sin el prefijo público) desde un componente de cliente filtra ese código al bundle del navegador. El paquete server-only mencionado antes existe justamente para que ese error se note en el build y no en producción.
Asumir que cada fetch dentro de un componente de servidor dispara una petición nueva también genera sorpresas: durante un mismo render, Next.js deduplica automáticamente las llamadas idénticas, así que varios componentes pueden pedir la misma URL sin multiplicar el tráfico real hacia esa fuente de datos.
Comparativa con otras formas de renderizar
Elegir entre CSR, SSR tradicional y componentes de servidor depende de cuánta interactividad necesita cada parte de la pantalla, no de la aplicación entera. En la práctica, casi toda app real termina mezclando varias de estas opciones en distintas secciones de la misma página:
OpciónCuándo usarlaVentajaLimitaciónClient-Side Rendering (SPA clásica)Interfaces muy interactivas donde el SEO no es críticoInteractividad inmediata una vez cargadaBundle grande y pantalla en blanco mientras carga el JSServer-Side Rendering tradicionalPáginas que necesitan HTML completo y datos frescos en cada visitaPrimera pintura rápida con contenido realEl componente entero se re-ejecuta en cada request, incluida la parte sin interactividadServer Components (RSC)Partes de la UI que leen datos pero no necesitan estado ni eventosCero JavaScript enviado por ese componente puntualNo pueden usar hooks de estado ni listeners del navegadorClient Components ('use client')Botones, formularios y cualquier UI con estado localAcceso completo a useState, useEffect y eventosSu código sí viaja al navegador y cuenta para el bundle
Profundizando: el RSC Payload y el streaming
El RSC Payload no es HTML: es un formato propio, parecido a JSON pero con referencias especiales a los módulos de cliente, que describe el árbol ya resuelto. Esa separación es la que permite que el servidor empiece a enviar partes del árbol antes de terminar de resolver todo: si un componente de servidor tiene un fetch lento envuelto en <Suspense>, React manda primero el resto de la página y completa esa sección cuando la promesa resuelve, en el mismo viaje de red.
Esa frontera entre servidor y cliente también es una jerarquía, no una mezcla libre: un componente de servidor puede importar y renderizar uno de cliente, pero un componente de cliente no puede importar directamente uno de servidor (si lo intenta, Next.js lo convierte automáticamente en un componente de cliente más, perdiendo el beneficio). La forma correcta de combinarlos cuando hace falta es pasar el componente de servidor ya renderizado como children hacia el de cliente.
Esta frontera explícita es, en el fondo, la decisión de diseño detrás de todo RSC: en vez de que el framework adivine qué parte conviene renderizar dónde, el propio código declara su entorno con una directiva de una línea, y React arma el resto del árbol alrededor de esa declaración. La revalidación de datos sigue la misma lógica declarativa: Next.js permite etiquetar un fetch con un tag de caché y después invalidar solo ese tag, en vez de recalcular la página entera cada vez que cambia un dato puntual.
Next.js marcó el App Router, que usa RSC por defecto, como estable en su versión 13.4 de mayo de 2023.
📖 Resumen en Telegram: Ver resumen
Tu próximo paso: tomá el componente PostsPage de este artículo, corré npx create-next-app@latest y agregale un LikeButton propio para ver con tus propios ojos, en la pestaña Network del navegador, qué código sí viaja y cuál se queda en el servidor.
Preguntas frecuentes
¿Los React Server Components reemplazan a Next.js?
No. RSC es una funcionalidad de React mismo; Next.js es uno de los frameworks que la implementan con un servidor, un router y las convenciones de archivos necesarias para que funcione. React por sí solo no incluye un servidor.
¿Puedo usar componentes de servidor sin un framework?
En teoría sí, porque la especificación vive en paquetes como react-server-dom-webpack, pero en la práctica hace falta integrar un bundler y un servidor que sepan generar y consumir el RSC Payload. Casi nadie lo hace a mano: se usa a través de Next.js u otro framework compatible.
¿RSC mejora el SEO?
Mejora el tiempo hasta el primer contenido útil porque el HTML llega completo desde el servidor, lo que ayuda a los rastreadores que no ejecutan JavaScript. Pero el SEO también depende de metadatos, de la estructura semántica y de la velocidad general, no solo de dónde se renderiza cada componente.
¿Qué diferencia hay entre un componente de servidor y Server-Side Rendering tradicional?
SSR tradicional renderiza todo el árbol en el servidor en cada visita, pero ese mismo código vuelve a bajar al navegador para hidratarse. Un componente de servidor nunca baja: su código y su render quedan exclusivamente del lado del servidor para siempre.
¿Create React App soporta RSC?
No. Create React App genera una aplicación puramente de cliente, y el equipo de React dejó de recomendarlo precisamente porque no tiene la parte de servidor necesaria para RSC. Los frameworks recomendados hoy son Next.js y otros que adopten la misma arquitectura.
¿Los componentes de servidor pueden consultar una base de datos SQL directamente?
Sí, y es uno de sus usos más comunes: al no viajar nunca al navegador, el componente puede importar un cliente de PostgreSQL o MySQL, ejecutar la consulta y renderizar el resultado sin exponer la cadena de conexión en ningún archivo público.
Referencias
- react.dev: referencia oficial de React sobre Server Components.- react.dev/blog: anuncio original de React Server Components en 2020.- nextjs.org: documentación de Next.js sobre cómo implementa Server Components en el App Router.- react.dev/blog: anuncio de React 19 estable, diciembre de 2024.
📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.
Top comments (0)