Carga y Manejo de Errores
Los archivos especiales loading.tsx, error.tsx y not-found.tsx crean límites Suspense y Error Boundaries automáticos con alcance a segmentos de ruta.
Busca en todas las páginas de la documentación
Los archivos especiales loading.tsx, error.tsx y not-found.tsx crean límites Suspense y Error Boundaries automáticos con alcance a segmentos de ruta.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Tarjeta de referencia rápida - lista para copiar y pegar.
app/
├── loading.tsx # Fallback de carga global
├── error.tsx # Error boundary global
├── not-found.tsx # 404 global
└── dashboard/
├── loading.tsx # Fallback de carga para /dashboard
├── error.tsx # Error boundary para /dashboard
└── page.tsx
// app/dashboard/loading.tsx
export default function Loading() {
return <div className="animate-pulse">Cargando dashboard...</div>;
}
// app/dashboard/error.tsx
"use client";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return (
<div>
<h2>Algo salió mal</h2>
<button onClick={reset}>Intentar de nuevo</button>
</div>
);
}Cuándo usarlo: Cada segmento de ruta que obtiene datos debe tener un loading.tsx. Cada segmento donde los errores son recuperables debe tener un error.tsx.
// app/dashboard/loading.tsx - Estado de carga esqueleto
export default function DashboardLoading() {
return (
<div className="space-y-4 p-6">
<div className="h-8 w-48 animate-pulse rounded bg-gray-200" />
<div className="grid grid-cols-3 gap-4">
{Array.from({ length: 3 }).map((_, i) => (
<div key={i} className="h-32 animate-pulse rounded-lg bg-gray-200" />
))}
</div>
<div className="h-64 animate-pulse rounded-lg bg-gray-200" />
</div>
);
}// app/dashboard/error.tsx - Debe ser un Client Component
"use client";
import { useEffect } from "react";
export default function DashboardError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
// Registrar error en el servicio de monitoreo
console.error("Error del dashboard:", error);
}, [error]);
return (
<div className="flex flex-col items-center justify-center p-12">
<h2 className="text-xl font-bold text-red-600">Error del Dashboard</h2>
<p className="mt-2 text-gray-600">
{error.message || "Ocurrió un error inesperado."}
</p>
{error.digest && (
<p className="mt-1 text-sm text-gray-400">ID de Error: {error.digest}</p>
)}
<button
onClick={reset}
className="mt-4 rounded bg-blue-600 px-4 py-2 text-white hover:bg-blue-700"
>
Intentar de Nuevo
</button>
</div>
);
}// app/dashboard/page.tsx - Server Component que podría fallar
import { notFound } from "next/navigation";
async function getDashboardData() {
const res = await fetch("https://api.example.com/dashboard", {
next: { revalidate: 60 },
});
if (res.status === 404) notFound();
if (!res.ok) throw new Error("No se pudo cargar los datos del dashboard");
return res.json();
}
export default async function DashboardPage() {
const data = await getDashboardData();
return (
<div className="p-6">
<h1 className="text-2xl font-bold">Dashboard</h1>
<div className="mt-4 grid grid-cols-3 gap-4">
<StatCard label="Ingresos" value={data.revenue} />
<StatCard label="Usuarios" value={data.users} />
<StatCard label="Pedidos" value={data.orders} />
</div>
</div>
);
}
function StatCard({ label, value }: { label: string; value: number }) {
return (
<div className="rounded-lg border p-4">
<p className="text-sm text-gray-500">{label}</p>
<p className="text-2xl font-bold">{value.toLocaleString()}</p>
</div>
);
}// app/not-found.tsx - Página personalizada 404
import Link from "next/link";
export default function NotFound() {
return (
<div className="flex min-h-screen flex-col items-center justify-center">
<h1 className="text-6xl font-bold">404</h1>
<p className="mt-4 text-xl text-gray-600">Página no encontrada</p>
<Link
href="/"
className="mt-6 rounded bg-blue-600 px-6 py-2 text-white hover:bg-blue-700"
>
Ir a Inicio
</Link>
</div>
);
}loading.tsx envuelve la página en un límite <Suspense>. Next.js genera automáticamente <Suspense fallback={<Loading />}><Page /></Suspense>. La interfaz de carga se muestra instantáneamente mientras la página se transmite.error.tsx envuelve la página en un Error Boundary de React. Captura errores de JavaScript en la página y sus hijos durante el renderizado. La función reset vuelve a renderizar el contenido del error boundary.error.tsx debe ser un Client Component. Los Error Boundaries son una característica de React del lado del cliente. Siempre agrega "use client" al inicio.error.tsx no captura errores en el layout del mismo nivel. El error boundary se sitúa entre el layout y la página. Para capturar errores de layout, coloca error.tsx en el segmento padre.not-found.tsx se activa en llamadas notFound() o rutas no coincidentes. El not-found.tsx raíz es el fallback para todas las URLs no coincidentes. El not-found.tsx anidado solo se activa cuando llamas explícitamente a notFound().loading.tsx. El layout se renderiza inmediatamente, el fallback de carga se muestra, y el contenido de la página se transmite cuando está listo.// Carga anidada - solo el segmento más interno muestra carga
// app/dashboard/settings/loading.tsx
export default function SettingsLoading() {
return <p>Cargando configuración...</p>;
// El layout del dashboard y la barra lateral permanecen visibles
}// Error boundary global - captura errores en toda la aplicación
// app/global-error.tsx
"use client";
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<html>
<body>
<h1>Algo salió muy mal</h1>
<button onClick={reset}>Intentar de nuevo</button>
</body>
</html>
);
}
// Nota: global-error.tsx reemplaza el layout raíz, así que debe incluir <html> y <body>// Límites Suspense manuales para estados de carga granulares
// app/dashboard/page.tsx
import { Suspense } from "react";
export default function DashboardPage() {
return (
<div className="grid grid-cols-2 gap-4">
<Suspense fallback={<Skeleton />}>
<RevenueChart />
</Suspense>
<Suspense fallback={<Skeleton />}>
<UserTable />
</Suspense>
</div>
);
}
async function RevenueChart() {
const data = await getRevenue(); // se transmite independientemente
return <div>{/* chart */}</div>;
}
async function UserTable() {
const users = await getUsers(); // se transmite independientemente
return <table>{/* rows */}</table>;
}
function Skeleton() {
return <div className="h-48 animate-pulse rounded bg-gray-200" />;
}// Tipo de props de error.tsx
interface ErrorProps {
error: Error & { digest?: string }; // digest es un hash de error del lado del servidor
reset: () => void; // vuelve a renderizar el error boundary
}
// loading.tsx y not-found.tsx no aceptan props
// Son componentes simples sin parámetros
// global-error.tsx tiene los mismos props que error.tsx
// pero debe renderizar su propio <html> y <body>error.tsx debe tener "use client". Olvidarlo causa un error de compilación. Los Error Boundaries son inherentemente del lado del cliente.error.tsx no puede capturar errores en su layout.tsx hermano. El boundary envuelve la página, no el layout. Usa un error.tsx padre para capturar errores de layout.global-error.tsx solo se activa en producción. En desarrollo, aparece la superposición de errores de Next.js.global-error.tsx debe incluir <html> y <body>. Reemplaza completamente el layout raíz cuando se activa.notFound() de next/navigation lanza un error. El código después de notFound() es inalcanzable. TypeScript podría no advertir sobre esto.loading.tsx se muestra en la carga inicial y navegaciones posteriores. Aparece cada vez que el componente de página del segmento está pendiente.reset() solo funciona para errores del lado del cliente. Si un Server Component lanza un error, reset() intenta volver a renderizar pero el mismo error del servidor puede repetirse sin una corrección de código o cambio de datos.| Enfoque | Cuándo Usarlo |
|---|---|
Límite <Suspense> manual | Estados de carga granulares dentro de una sola página |
| Librería de React Error Boundary | Manejo personalizado de errores en Client Components |
try/catch en Server Components | Manejo de errores sin mostrar el error boundary |
| Redirección en error | Enviar usuarios a una página diferente en lugar de mostrar una interfaz de error |
unstable_rethrow | Relanzar errores internos de Next.js (redirecciones, notFound) desde bloques catch |
Los Error Boundaries son una característica de React del lado del cliente. Se basan en métodos de ciclo de vida componentDidCatch que solo existen en el cliente. Debes agregar "use client" al inicio de cada archivo error.tsx.
No. El error boundary envuelve la página, no el layout del mismo nivel. Para capturar errores de layout, coloca error.tsx en el segmento padre.
error.tsx captura errores dentro de un segmento de ruta específicoglobal-error.tsx captura errores en toda la aplicación, incluidos errores del layout raízglobal-error.tsx debe incluir su propio <html> y <body> porque reemplaza el layout raízglobal-error.tsx solo se activa en producción; en desarrollo, aparece la superposición de errores de Next.jsNext.js genera <Suspense fallback={<Loading />}><Page /></Suspense> internamente. La interfaz de carga se renderiza instantáneamente mientras el contenido de la página se transmite.
Se muestra en la carga inicial y en cada navegación posterior a ese segmento. Cada vez que el componente de página está pendiente, el fallback de carga aparece.
not-found.tsx raíz se activa automáticamente para todas las URLs no coincidentesnot-found.tsx anidado solo se activa cuando llamas explícitamente a notFound() de next/navigationVuelve a renderizar el contenido del error boundary, intentando renderizar la página de nuevo. Para errores del lado del cliente, esto vuelve a intentar el renderizado. Para errores del servidor, el mismo error puede repetirse sin un cambio de datos o código.
import { Suspense } from "react";
export default function Page() {
return (
<div className="grid grid-cols-2 gap-4">
<Suspense fallback={<Skeleton />}>
<RevenueChart />
</Suspense>
<Suspense fallback={<Skeleton />}>
<UserTable />
</Suspense>
</div>
);
}Cada componente asincrónico se transmite independientemente.
interface ErrorProps {
error: Error & { digest?: string };
reset: () => void;
}La propiedad digest es un hash de error del lado del servidor útil para el registro.
notFound() lanza un error internamente, así que el bloque catch lo interceptará. Usa unstable_rethrow en bloques catch para relanzar errores internos de Next.js como notFound() y redirect().
No. Ambos son componentes simples sin parámetros. No reciben props de Next.js.
loading.tsx de cada segmento muestra un fallback para su parte de la páginanotFound() y redirect()Revisado por Chris St. John·Última actualización: 10 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥