React Framework

Next.js

Next.js es el framework de React que añade routing, renderizado en el servidor, obtención de datos y un runtime de servidor, permitiéndote construir una aplicación completa en lugar de ensamblar una.

intermediate16 min readUpdated 15 sept 2026
page.tsx
tsx
// app/users/page.tsx
async function getUsers() {
  const res = await fetch("https://api.example.com/users", {
    next: { revalidate: 60 },
  });
  if (!res.ok) throw new Error("Failed to fetch users");
  return res.json();
}

export default async function UsersPage() {
  const users = await getUsers();

  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}
Basado en
React
Router
App Router (app/)
Renderizado
Server and client components
Datos
Server fetch + server actions
Bundler
Turbopack (webpack fallback)
Despliegue
Vercel, Node, Docker, static

Por que importa

Por qué Next.js lidera el ecosistema de React

Renderizado en el servidor por defecto

Los componentes se renderizan primero en el servidor, por lo que las páginas llegan como HTML y pueden leer datos sin necesidad de un viaje de ida y vuelta del cliente.

Routing basado en el sistema de archivos

Las carpetas y archivos bajo app/ se convierten en rutas, layouts y estados de carga, sin necesidad de mantener una configuración de rutas.

Optimizado desde el inicio

El framework incluye optimizaciones de imágenes, fuentes, scripts y bundles, por lo que los valores predeterminados de rendimiento son excelentes.

La imagen completa

Las tres ideas detrás de Next.js

El sistema de archivos es el router, los componentes pueden renderizarse en el servidor y el runtime de servidor es parte del framework.

El App Router

Routing

Un router basado en el sistema de archivos con layouts anidados, estados de carga, error boundaries y streaming.

Server components

Renderizado

Componentes que se ejecutan en el servidor y envían HTML, utilizando client components para la interactividad.

El server runtime

Backend

Los route handlers y server actions te permiten escribir lógica de backend en el mismo proyecto.

Next.js de un vistazo

Lo que te ofrece el App Router

Routing basado en archivos

Las carpetas se mapean a segmentos de URL y los archivos definen páginas, layouts y estados especiales.

Layouts anidados

Comparte UI entre rutas con layouts que preservan el estado durante la navegación.

Server components

Obtén datos y renderiza en el servidor sin enviar ese código al navegador.

Server actions

Llama a funciones del servidor directamente desde formularios y manejadores de eventos, con mejora progresiva.

Route handlers

Crea endpoints de API como funciones de Request y Response estándar de la web.

Optimización integrada

El framework gestiona imágenes, fuentes, scripts y streaming.

Una breve historia

De un complemento de React a una plataforma full-stack

  1. 2016

    Next.js 1

    Vercel lanza un pequeño framework de React con renderizado en el servidor y routing basado en archivos.

    16
  2. 2018

    Next.js 7

    Las mejoras en el rendimiento de compilación y la experiencia del desarrollador amplían su adopción.

    18
  3. 2020

    Next.js 10

    El componente Image y las analíticas convierten las preocupaciones de producción en ciudadanos de primera clase.

    20
  4. 2022

    Next.js 13

    El App Router y los React Server Components transforman la manera de construir aplicaciones con Next.js.

    22
  5. Hoy

    Una plataforma full-stack

    Los server actions, el partial prerendering y Turbopack convierten a Next.js en un stack de aplicación completo.

    Hoy

La guia completa

Next.js: Todo lo que necesitas saber

¿Qué es Next.js?

Next.js es un framework de React que transforma una librería de UI en una plataforma de aplicaciones completa. Añade enrutamiento basado en archivos, renderizado en el servidor, obtención de datos (data fetching), endpoints de API, optimización de imágenes y fuentes, y un runtime de servidor. En lugar de elegir y configurar manualmente un router, una capa de datos y un entorno de compilación, obtienes un stack coherente diseñado para trabajar en conjunto.

Está mantenido por Vercel y se ha convertido en la forma predeterminada de construir aplicaciones de React para producción. El modelo actual es el App Router, basado en React Server Components, el cual cambia dónde se ejecuta tu código y cómo fluyen los datos.

El App Router y el enrutamiento basado en archivos

Las rutas provienen del sistema de archivos. Una carpeta representa un segmento de la URL, y un archivo page.tsx la convierte en una ruta.

app/
├── layout.tsx          # root layout, wraps everything
├── page.tsx            # /
├── about/page.tsx      # /about
├── blog/
│   ├── page.tsx        # /blog
│   └── [slug]/page.tsx # /blog/:slug
└── dashboard/
    ├── layout.tsx      # layout for /dashboard/*
    └── page.tsx        # /dashboard

Los segmentos dinámicos utilizan corchetes, y los layouts se anidan para que la UI compartida permanezca montada durante la navegación. Archivos especiales como loading.tsx, error.tsx y not-found.tsx gestionan los estados correspondientes sin necesidad de código adicional.

// app/blog/[slug]/page.tsx
export default async function PostPage({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  const post = await getPost(slug);
  return <article>{post.content}</article>;
}

Componentes de servidor y de cliente

Este es el concepto que define al Next.js moderno. Por defecto, los componentes son server components: se renderizan en el servidor, pueden leer datos y secretos directamente y no añaden nada al bundle del navegador. Los componentes que requieren interactividad optan por ello mediante "use client".

// app/counter.tsx
"use client";

import { useState } from "react";

export function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

Un server component puede importar y renderizar un client component, pero no al revés. La regla de oro: mantén los componentes en el servidor y desplaza "use client" hacia la hoja interactiva más pequeña. De esta forma, el JavaScript que envías al navegador se mantiene reducido.

Obtención de datos

En el App Router, obtienes los datos en los server components utilizando la función estándar fetch, la cual ha sido extendida con opciones de almacenamiento en caché y revalidación.

// app/posts/page.tsx
async function getPosts() {
  const res = await fetch("https://api.example.com/posts", {
    next: { revalidate: 60 },
  });
  if (!res.ok) throw new Error("Failed to load posts");
  return res.json();
}

export default async function PostsPage() {
  const posts = await getPosts();
  return <PostList posts={posts} />;
}

Dado que el código se ejecuta en el servidor, no es necesario configurar indicadores de carga (loading spinners) ni existen cascadas (waterfalls) en el cliente. Puedes revalidar los datos basándote en el tiempo, bajo demanda mediante revalidatePath o revalidateTag, o bien desactivar el almacenamiento en caché por completo. Además, las solicitudes fetch se deduplican dentro de un mismo renderizado.

Route handlers y server actions

Para los endpoints de la API, los route handlers exportan funciones que reciben un web Request y devuelven un Response.

// app/api/posts/route.ts
export async function GET() {
  const posts = await db.post.findMany();
  return Response.json(posts);
}

export async function POST(request: Request) {
  const body = await request.json();
  const post = await db.post.create({ data: body });
  return Response.json(post, { status: 201 });
}

Para las mutaciones desde tu propia UI, los server actions suelen ser más sencillos. Marca una función con "use server" y llámala desde un formulario o un manejador de eventos.

// app/posts/new/page.tsx
import { revalidatePath } from "next/cache";

async function createPost(formData: FormData) {
  "use server";
  await db.post.create({ data: { title: String(formData.get("title")) } });
  revalidatePath("/posts");
}

export default function NewPost() {
  return (
    <form action={createPost}>
      <input name="title" required />
      <button type="submit">Create</button>
    </form>
  );
}

Los server actions gestionan la validación, las escrituras en la base de datos y la revalidación de la caché de forma conjunta, y el formulario funciona incluso antes de que JavaScript se cargue. Eso es mejora progresiva sin trabajo adicional.

Renderizado y almacenamiento en caché

Next.js soporta varias estrategias de renderizado en una misma aplicación:

  • Las páginas estáticas se prerenderizan en el momento del build.
  • Las páginas renderizadas en el servidor se generan por cada solicitud.
  • El streaming envía el HTML en fragmentos para que los datos lentos no bloqueen la estructura principal (shell).
  • El renderizado en el cliente gestiona las islas interactivas después de la hidratación.

El almacenamiento en caché tiene varias capas, desde el fetch cache hasta el route cache completo. Comprenderlas es la principal curva de aprendizaje, y los valores por defecto están diseñados para ser rápidos. Cuando sientas que algo está desactualizado, la solución suele ser una llamada de revalidación explícita en lugar de desactivar el almacenamiento en caché en todas partes.

Optimización integrada

Next.js incluye componentes que gestionan las tareas de rendimiento más comunes:

  • next/image redimensiona, carga mediante lazy-loading y sirve formatos modernos.
  • next/font aloja las fuentes localmente y elimina el layout shift.
  • next/script controla cómo se cargan los scripts de terceros.
  • Turbopack acelera el desarrollo y las compilaciones de producción.

Estos valores predeterminados significan que una aplicación de Next.js bien construida es rápida sin necesidad de un proyecto de optimización independiente.

Mejores prácticas

  • Mantén los componentes en el servidor y usa "use client" solo donde sea necesario.
  • Obtén los datos en server components en lugar de hacerlo en effects.
  • Utiliza server actions para las mutaciones y revalida explícitamente.
  • Coloca rutas, componentes y acceso a datos juntos bajo app/.
  • Añade loading.tsx y error.tsx para ofrecer una buena UX en los límites de las rutas.
  • Prefiere los componentes de imagen y fuentes del framework antes que el manejo manual.
  • Comprende el funcionamiento del caching antes de desactivarlo; opta por una revalidación dirigida.

Errores comunes

  • Esparcir "use client" en la parte superior del árbol y perder los beneficios del servidor.
  • Hacer fetch en useEffect cuando un server component sería suficiente.
  • Olvidar revalidar después de una mutación y mostrar datos obsoletos.
  • Asumir que las API de App Router y Pages Router son intercambiables.
  • Bloquear una ruta debido a datos lentos en lugar de usar streaming con Suspense.
  • Tratar a Next.js solo como una herramienta de front-end y reconstruir un backend independiente.

Próximos pasos

Next.js es la forma más completa de desplegar React hoy en día. Refuerza tus bases de React y TypeScript, compara su modelo con Remix y Astro, y aprende sobre el runtime de Node.js donde se despliega. Después, construye una pequeña aplicación full-stack que incluya un server component, un route handler y una server action.

Obtención de datos

En el App Router, obtén los datos en un server component. No hay estado de carga que gestionar ni peticiones desde el navegador.

Preferido
export default async function Page() {
  const res = await fetch("/api/posts");
  const posts = await res.json();
  return <PostList posts={posts} />;
}
Evitar
"use client";
export default function Page() {
  const [posts, setPosts] = useState([]);
  useEffect(() => {
    fetch("/api/posts")
      .then((r) => r.json())
      .then(setPosts);
  }, []);
  return <PostList posts={posts} />;
}

Mutación de datos

Los server actions se ejecutan en el servidor y funcionan sin JavaScript, por lo que los formularios se mantienen simples.

Preferido
async function createPost(formData) {
  "use server";
  await db.post.create({
    title: formData.get("title"),
  });
  revalidatePath("/posts");
}

<form action={createPost}>
  <input name="title" />
</form>
Evitar
async function onSubmit(e) {
  e.preventDefault();
  await fetch("/api/posts", {
    method: "POST",
    body: JSON.stringify(data),
  });
}

Preguntas frecuentes

Preguntas frecuentes

Keep learning

Related topics from the roadmap.

$ comienza a aprender

Listo para aprender Next.js?

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