Hace tiempo que sabemos dejar a un agente escribir código que pasa tests; incluso sabemos cómo montar un equipo de agentes de IA. Lo que no sabíamos era hacerle escribir código que se sienta rápido. “Que la navegación sea instantánea” es un requisito difuso: no hay assertion de Jest para “esto da buen feeling”. Un agente puede refactorizar a ciegas, medir a ojo, y declarar victoria sin que nada haya mejorado de verdad.
Vercel acaba de contar cómo resolvieron exactamente eso en v0, su plataforma de generación de apps: un agente en bucle, armado con un test determinista y un Skill con patrones, que dejó las navegaciones de producción prácticamente a cero. Y lo interesante no es el caso de éxito de marketing, es la pieza técnica que lo hace posible y que ya puedes usar en tu app: el helper instant() que trae Next.js 16.3.

El problema: apps dinámicas que “parecen web”
En una app server-driven con React Server Components, navegar suele implicar un roundtrip de red: clicas, no pasa nada, responde el servidor, aparece la página. Hasta ahora Next.js ofrecía dos salidas: prerenderizar estáticamente en build (imposible con datos personales por usuario) o marcar los links con prefetch completo (caro y con un prefetch request por link, algo que el propio equipo admite en su post de Next.js 16.3 que quedaba ridículo: veinte chats en un sidebar, veinte requests).
La solución de la 16.3, llamada Instant Navigations, copia el truco de las SPAs: en vez de prefetch por link, Next.js prefetchea un shell reutilizable por ruta, cacheado en el cliente. El shell contiene todo lo que puede mostrarse sin esperar al servidor: el layout, los títulos, los skeletons. Al click, el shell aparece al instante y el contenido dinámico llega después por streaming.
Para activarlo hay dos flags en next.config.ts:
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
cacheComponents: true,
partialPrefetching: true,
};
export default nextConfig;
Con cacheComponents activado, cuando una ruta hace await de datos en el servidor tienes tres opciones, que es la parte conceptual importante:
- Stream con
<Suspense>: el usuario ve al instante el fallback, y el contenido entra después. - Cache con
'use cache': el usuario ve UI cacheada de una ejecución anterior. - Block: si prefieres que esa ruta espere al servidor (un post de blog que no quieres mostrar como skeleton), lo declaras explícitamente con
export const instant = falseen la página o el layout.
En desarrollo, el panel Instant Insights te señala automáticamente qué rutas no son instantáneas, convirtiendo la navegación lenta en un error visible en vez de una sensación vaga.
La pieza clave: un test que verifica que es “rápido”
Aquí está lo que cambia el juego para los agentes. Next.js 16.3 incluye un helper para Playwright, instant(), importado desde @next/playwright, que pausa la navegación y te deja comprobar qué partes de la UI son visibles sin request de red:
import { expect, test } from '@playwright/test';
import { instant } from '@next/playwright';
test('navegar a chats es instantáneo', async ({ page }) => {
await page.goto('/');
await instant(page, async () => {
await page.getByRole('link', { name: 'Chats' }).click();
await expect(page.getByTestId('app-title')).toBeVisible();
});
});
Si el contenido esperado depende de la red, el test falla. Fíjate en lo que significa esto: un requisito cualitativo (“que se sienta instantáneo”) acaba de convertirse en una comprobación binaria y determinista. Y las comprobaciones binarias y deterministas son exactamente el combustible que un bucle agéntico necesita.
El bucle que dejó v0 instantáneo
El caso práctico lo publicaron en Making Navigations Instant in v0. El bucle es el clásico de agentes bien hecho, con las tres cosas que siempre digo que hacen falta: un objetivo verificable, guardarraíles con patrones probados —como los que defines en AGENTS.MD—, y feedback real de producción:
- Definir el objetivo como test que falla: el agente escribe un test con
instant()para una navegación lenta concreta (por ejemplo, de/a/chats). - Aplicar el fix usando los patrones del Skill: refactorizar hasta que el test pasa.
- Repetir si no pasa: el test es la condición de salida del bucle.
- Commitear el código Y el test: el test se queda en CI como guardia anti-regresiones.
El Skill que contiene los patrones se instala con:
npx skills add vercel/next.js --skill next-cache-components-optimizer
Y luego se le da al agente un prompt tan simple como “Make the navigation from ’/’ to ‘/chats’ instant using the next-cache-components-optimizer skill”. El Skill es la parte que no hay que subestimar: sin él, el agente improvisa refactors; con él, aplica recetas verificadas para cada tipo de bloqueo (patrones de routes paralelas, auth gates, shells vacíos, skeletons responsive).
¿Y qué pinta tienen los fixes? En la mayoría de casos, algo sorprendentemente modesto: bajar el acceso a datos dinámico por debajo de un boundary de Suspense, para que el resto de la página entre en el shell:
// antes: el await bloquea toda la página
export default async function WorkspacePage() {
const session = await getServerSession();
const team = await fetchTeam(session);
return <TeamSettings team={team} />;
}
// después: el shell pinta al instante, los datos entran por streaming
export default function WorkspacePage() {
return (
<SettingsPageLayout>
<SettingsHeader title="Workspace" />
<Suspense fallback={<WorkspaceSkeleton />}>
<WorkspaceContent />
</Suspense>
</SettingsPageLayout>
);
}
async function WorkspaceContent() {
const session = await getServerSession();
const team = await fetchTeam(session);
return <TeamSettings team={team} />;
}
Otros casos fueron refactors más gordos, como sacar una dependencia bloqueante del root layout y moverla a los componentes que la usan. Justo el tipo de cambio que toca varias features y que un humano procrastina durante meses, pero que un bucle test-driven ataca sin drama.
El resultado: la home (logueada y sin loguear), la página de detalle de chat y todas las subpáginas de settings pasaron de bloqueantes a instantáneas, con 16 tests nuevos que ahora impiden que cualquier cambio futuro —humano o agéntico— las vuelva lentas. Ese último punto es el que más me gusta: si tus agentes van a seguir tocando el repo, necesitas verificadores que les pongan límites, y “no rompas las navegaciones instantáneas” acaba de convertirse en uno.
Cómo activar navegaciones instantáneas en Next.js 16.3
La 16.3 salió como preview en junio (anuncio oficial) y se instala desde el tag preview de npm:
npm install next@preview
Si tu app aún no usa Cache Components, hay un segundo Skill, next-cache-components-adoption, que guía al agente por la migración. Ambos están documentados en la guía de AI agents con Next.js y en la doc de Instant Navigations.
Mi sugerencia de orden: activa cacheComponents en una rama, mira qué te escupe Instant Insights en desarrollo, escribe (o deja que el agente escriba) un test con instant() para tu navegación más importante, y lanza el bucle solo sobre esa. No migres media app de golpe: una navegación verde en CI vale más que veinte promesas.
La lección de fondo va más allá de Next.js. Los frameworks que ganen en la era de los agentes no serán los que generen más código, sino los que exporten verificadores: primitivas que conviertan cualidades difusas —rapidez percibida, accesibilidad, UX— en tests deterministas. Es el mismo principio que convertir capturas en tests con Claude Code y TestSprite; aquí el verificador es instant() y la cualidad es la velocidad percibida.
Preguntas frecuentes
¿Necesito usar v0 o Vercel para esto?
No. El helper instant(), los flags y los Skills son parte de Next.js open source. El caso de v0 es solo la demostración; el bucle funciona en cualquier app Next.js 16.3 con Cache Components.
¿Esto es lo mismo que Partial Prerendering?
No. PPR prerenderiza en build time; aquí el prerenderizado del shell ocurre en runtime, mientras el usuario navega, y se cachea en el navegador. El propio equipo de Vercel insiste en la distinción: conseguir navegaciones instantáneas es bastante menos trabajo que una migración a PPR estático.
¿Qué pasa si una ruta quiero que siga siendo server-bound?
Lo declaras con export const instant = false en la página o el layout, y el error de Instant Insights desaparece. Tú decides qué rutas se fuerzan a instant y cuáles no.



¿Qué te ha parecido?
Déjame tu opinión, pregunta o sugerencia. Los comentarios se sincronizan con GitHub Discussions .