NextQuery: etiqueta y revalida tus fetch por tag en el App Router
October 07, 2026 · 4 min read · Angel LM

NextQuery es una librería pequeña para el App Router de Next.js que hace tres cosas: te deja etiquetar tus fetch nativos, revalidarlos por tag cuando los datos cambian y ver cada fetch etiquetado en un panel mientras ejecutas next dev. Lo que no pasa por fetch (un ORM, un SDK) entra en los mismos tags con query().
El problema
La caché de datos de Next es potente, pero difícil de ver. Etiquetas un fetch con next: { tags }, llamas a revalidateTag() en una Server Action… y no sabes si ese fetch está en caché, cuánto le queda para quedar obsoleto o si la revalidación llegó a todas las páginas que lo usan.
Y si tus datos vienen de Prisma, Stripe o axios, ni siquiera pasan por el fetch de Next, así que no puedes etiquetarlos igual.
NextQuery cubre los dos huecos con muy poca API: revalidate(), tags(), query() y el componente <NextQuery />.
Instalación
pnpm add @angelitolm/next-queryInstálalo como dependencia normal, no de desarrollo: revalidate(), tags() y query() también se ejecutan en producción. Solo el panel es exclusivo de desarrollo.
Requisitos: Next.js 15 o 16 con App Router y React 19.
Etiqueta un fetch
No hace falta importar nada: es Next normal. Añade next.tags a un fetch en un Server Component:
export default async function Page() {
const res = await fetch(`${API}/products`, { next: { tags: ['products'], revalidate: 60 } })
const products: { id: number; name: string }[] = await res.json()
return (
<ul>
{products.map((p) => (
<li key={p.id}>{p.name}</li>
))}
</ul>
)
}revalidate son los segundos hasta que el dato queda obsoleto. Para que el fetch se cachee, define next.revalidate o cache: 'force-cache': un fetch sin ninguno de los dos puede no cachearse.
Revalida por tag
Cuando cambias los datos, llama a revalidate() desde una Server Action o un route handler:
'use server'
import { revalidate } from '@angelitolm/next-query'
export async function renameProduct(id: string, name: string) {
await db.rename(id, name)
revalidate('products') // revalidateTag('products', { expire: 0 })
}revalidate('products') expira el tag al instante, así que la siguiente lectura vuelve a pedir los datos.
Jerarquía de tags
Para revalidar un solo producto sin tirar toda la lista, usa el helper tags():
import { tags } from '@angelitolm/next-query'
fetch(url, { next: { tags: tags(['products', id]) } }) // ['products', 'products/1']Ahora cada producto lleva dos tags. revalidate(['products', id]) expira solo ese producto, y revalidate('products') sigue llegando a todos, porque todos comparten el tag products.
Datos que no son fetch: query()
Si el dato viene de un ORM, un SDK o axios, Next no puede cachearlo ni etiquetarlo. Para eso está query(): cachea el resultado de cualquier código de servidor bajo una clave y lo etiqueta igual que un fetch.
import { query } from '@angelitolm/next-query'
import { prisma } from '@/lib/prisma'
const product = await query(['products', id], () => prisma.product.findUnique({ where: { id } }))Un fetch y un query() que comparten tag se revalidan juntos. Si la lista viene de una API y el detalle de la base de datos, revalidate('products') expira ambos.
No envuelvas un
fetchenquery(): cachearías el mismo dato dos veces y las dos copias pueden desincronizarse. Si puedes etiquetar el fetch, etiquétalo.
El panel de desarrollo
Monta <NextQuery /> una sola vez en el layout raíz:
import { NextQuery } from '@angelitolm/next-query'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="es">
<body>
{children}
<NextQuery />
</body>
</html>
)
}Al ejecutar pnpm dev aparece un lanzador redondo en la esquina. Al abrirlo ves cada fetch etiquetado y cada query() con su estado, una barra de frescura que cuenta hacia atrás hasta quedar obsoleto, la respuesta y un botón ↻ para revalidar sus tags con un clic. Puedes filtrar por etiqueta o por tag y ordenar por actualización.
Fuera de desarrollo <NextQuery /> no renderiza nada y sus server actions se niegan a ejecutarse. Usa position="bottom-left" si prefieres la otra esquina.
Conclusiones
NextQuery no reemplaza la caché de Next: la hace visible y cómoda. Sigues usando fetch nativo, ganas una forma clara de revalidar por tag (con jerarquía si la necesitas), un camino para los datos que no son fetch y un panel para comprobar de un vistazo qué está en caché y qué no.
Pruébalo sin instalar nada en la demo en vivo, lee la documentación o mira el código en GitHub.
Written by
Angel LM
Full-stack developer passionate about creating beautiful and functional web applications. Sharing knowledge about React, Next.js, and modern web development.
Share