Fighting Stale Data: Debugging Next.js ISR on Azure Static Web Apps

The Problem
I recently deployed my personal portfolio using Next.js on Azure Static Web Apps. The build pipeline was clean, the site was fast, and the design was pixel-perfect.
Then I tried to update a blog post.
I updated the content in my CMS, triggered the revalidation API, and… nothing. The live site stubbornly showed the old content.
Locally? It worked perfectly.
In Production? Stale data.
This is the story of how I spent 4 hours debugging On-Demand Incremental Static Regeneration (ISR) and learned a hard lesson about distributed systems.
The "It Works on My Machine" Trap
My setup was standard. I was using the App Router with revalidateTag.
The Fetch Logic:
I was tagging my blog posts so I could purge them specifically:
async function getBlogPosts() {
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/blog`, {
next: {
tags: ['blog-posts'] // The target
},
})
return res.json()
}
The Revalidation Handler:
And here is the API route intended to purge that cache:
// app/api/revalidate/route.ts
import { NextRequest, NextResponse } from "next/server";
import { revalidateTag } from "next/cache";
export async function POST(request: NextRequest) {
// ... Auth checks ...
revalidateTag("blog-posts");
return NextResponse.json({ revalidated: true, now: Date.now() });
}
When I hit this endpoint locally, the cache cleared instantly. On Azure, the API returned 200 OK, but the content didn't change.
The Root Cause: Monolith vs. Distributed Systems
My mistake wasn't in the code; it was in my mental model of the infrastructure.
I was thinking like a VPS (Virtual Private Server) user. On a traditional VPS or a local machine, the server is a single "box." If you clear the cache on that box, it’s gone.
Azure Static Web Apps is not a box. It is a globally distributed, serverless system.
When I triggered revalidateTag in my Azure function, it was executing in a specific region or instance. However, the static content served to the user was cached at the edge (CDN). There was a disconnect between the serverless function handling the API request and the distributed edge nodes holding the cached HTML.
The propagation wasn't failing; it was inconsistent because I was treating a distributed microservices environment like a monolithic Express server.
The Solution: Path vs. Tag
While revalidateTag is powerful, I found that revalidatePath provided the consistency I needed for this specific Azure architecture.
Switching my strategy to target the specific route path forced the system to recognize the update more reliably in the Azure SWA environment.
// The fix that stabilized the deployment
revalidatePath("/blog");
The Takeaway
When you move from localhost to the cloud, you are no longer coding for a computer; you are coding for a network.
- Localhost lies. It hides the complexity of network propagation.
- Serverless is stateless. You cannot assume that "Server A" knows what "Server B" just did unless they share a synchronized state (or external storage like Redis).
- Read the platform docs. Next.js ISR behaves differently on Vercel, Azure, and AWS Amplify.
I built this portfolio to show off my skills, but this bug forced me to sharpen my backend architecture knowledge. The site is fast now—and more importantly, the data is fresh.