This project demonstrates the importance of revalidatePath() in Next.js 15 Server Actions when dealing with external data changes.
The Problem: When data changes externally (via webhooks, cron jobs, or other systems), calling a GET Server Action without revalidatePath() won't refresh the UI because the cache isn't invalidated.
The Solution: Using revalidatePath() in your GET Server Action invalidates the cache and allows Next.js to fetch fresh data.
# Install dependencies
npm install
# Run in development mode
npm run dev
# Build for production
npm run build
npm startOpen http://localhost:3000 in your browser.
- Click "🌍 Insert External" - simulates an external system adding data to the database
- Click "🔄 GET Server Action" - calls a GET Server Action WITHOUT
revalidatePath() - ❌ The new product doesn't appear because the cache wasn't invalidated
Why? Without revalidatePath(), Next.js uses cached data and doesn't know it needs to refetch.
- Click "🌍 Insert External" - simulates an external system adding data to the database
- Click "✅ GET + Revalidate" - calls a GET Server Action WITH
revalidatePath() - ✅ The new product appears immediately because the cache was invalidated
Why? revalidatePath() tells Next.js to invalidate the cache and fetch fresh data on the next render.
Functions that run 100% on the server, marked with 'use server':
'use server';
export async function refreshProducts(filters: FilterOptions) {
const products = await getFilteredProducts(filters);
// ✅ This is the key - invalidate the cache
revalidatePath('/solution');
return { success: true, products };
}Invalidates the Next.js cache for a specific path:
import { revalidatePath } from 'next/cache';
// Invalidate cache for a specific route
revalidatePath('/products');
// Invalidate cache for all routes
revalidatePath('/', 'layout');| Operation | Use revalidatePath? | Why? |
|---|---|---|
| GET (reading data after external change) | ✅ Yes | Cache needs to be invalidated |
| POST (creating data) | ✅ Yes | New data needs to be reflected |
| PUT (updating data) | ✅ Yes | Updated data needs to be shown |
| DELETE (removing data) | ✅ Yes | Removed data should disappear |
| Filter changes | ❌ No | URL change triggers refetch automatically |
| Pagination | ❌ No | URL change triggers refetch automatically |
nextjs-revalidation-demo/
├── app/
│ ├── problem/ # Demo WITHOUT revalidatePath
│ │ ├── actions.ts # Server Actions (no revalidate)
│ │ ├── page.tsx # Server Component
│ │ └── filter-controls.tsx # Client Component
│ │
│ ├── solution/ # Demo WITH revalidatePath
│ │ ├── actions.ts # Server Actions (with revalidate)
│ │ ├── page.tsx # Server Component
│ │ └── filter-controls.tsx # Client Component
│ │
│ └── api/
│ └── external-insert/ # API Route (simulates external system)
│
├── lib/
│ ├── db/
│ │ └── mock-db.ts # In-memory database
│ └── dal/
│ └── products.ts # Data Access Layer
│
└── components/
├── product-table.tsx
└── ui/ # UI components
- Next.js 15.1.8 - React framework with App Router
- React 19 - UI library
- TypeScript - Type safety
- Tailwind CSS - Styling
- Turbopack - Ultra-fast bundler
MIT
Este proyecto demuestra la importancia de revalidatePath() en Next.js 15 Server Actions cuando se trabaja con cambios de datos externos.
El Problema: Cuando los datos cambian externamente (vía webhooks, cron jobs, u otros sistemas), llamar a un GET Server Action sin revalidatePath() no actualizará la UI porque el cache no se invalida.
La Solución: Usar revalidatePath() en tu GET Server Action invalida el cache y permite a Next.js obtener datos frescos.
# Instalar dependencias
npm install
# Ejecutar en modo desarrollo
npm run dev
# Build para producción
npm run build
npm startAbre http://localhost:3000 en tu navegador.
- Haz clic en "🌍 Insertar Externo" - simula un sistema externo agregando datos a la base de datos
- Haz clic en "🔄 GET Server Action" - llama a un GET Server Action SIN
revalidatePath() - ❌ El nuevo producto no aparece porque el cache no fue invalidado
¿Por qué? Sin revalidatePath(), Next.js usa datos cacheados y no sabe que necesita re-obtener los datos.
- Haz clic en "🌍 Insertar Externo" - simula un sistema externo agregando datos a la base de datos
- Haz clic en "✅ GET + Revalidate" - llama a un GET Server Action CON
revalidatePath() - ✅ El nuevo producto aparece inmediatamente porque el cache fue invalidado
¿Por qué? revalidatePath() le dice a Next.js que invalide el cache y obtenga datos frescos en el siguiente render.
Funciones que se ejecutan 100% en el servidor, marcadas con 'use server':
'use server';
export async function refreshProducts(filters: FilterOptions) {
const products = await getFilteredProducts(filters);
// ✅ Esta es la clave - invalidar el cache
revalidatePath('/solution');
return { success: true, products };
}Invalida el cache de Next.js para una ruta específica:
import { revalidatePath } from 'next/cache';
// Invalidar cache para una ruta específica
revalidatePath('/products');
// Invalidar cache para todas las rutas
revalidatePath('/', 'layout');| Operación | ¿Usar revalidatePath? | ¿Por qué? |
|---|---|---|
| GET (leer datos después de cambio externo) | ✅ Sí | El cache necesita invalidarse |
| POST (crear datos) | ✅ Sí | Los nuevos datos deben reflejarse |
| PUT (actualizar datos) | ✅ Sí | Los datos actualizados deben mostrarse |
| DELETE (eliminar datos) | ✅ Sí | Los datos eliminados deben desaparecer |
| Cambio de filtros | ❌ No | El cambio de URL dispara refetch automáticamente |
| Paginación | ❌ No | El cambio de URL dispara refetch automáticamente |
nextjs-revalidation-demo/
├── app/
│ ├── problem/ # Demo SIN revalidatePath
│ │ ├── actions.ts # Server Actions (sin revalidate)
│ │ ├── page.tsx # Server Component
│ │ └── filter-controls.tsx # Client Component
│ │
│ ├── solution/ # Demo CON revalidatePath
│ │ ├── actions.ts # Server Actions (con revalidate)
│ │ ├── page.tsx # Server Component
│ │ └── filter-controls.tsx # Client Component
│ │
│ └── api/
│ └── external-insert/ # API Route (simula sistema externo)
│
├── lib/
│ ├── db/
│ │ └── mock-db.ts # Base de datos en memoria
│ └── dal/
│ └── products.ts # Capa de Acceso a Datos
│
└── components/
├── product-table.tsx
└── ui/ # Componentes UI
- Next.js 15.1.8 - Framework React con App Router
- React 19 - Librería UI
- TypeScript - Tipado estático
- Tailwind CSS - Estilos
- Turbopack - Bundler ultra-rápido
MIT
Made with ❤️ to help the Next.js community understand revalidation