Statically generated pages become stale when you publish or edit a post. Next.js Incremental Static Regeneration (ISR) lets you regenerate individual pages on-demand — without a full rebuild.
ISR tags
The SDK ships two ISR tag helpers:
import {
VLOZI_BLOG_TAG, // "vlozi-blog" — tags the entire blog (list + every post)
vloziPostTag, // (slug) => "vlozi-post:<slug>" — tags a single post
} from "@vlozi/blog/next";Wire them into your fetch() calls (or pass them to the VloziClient constructor) so Next.js knows which cache entries to invalidate when you revalidate.
Option A — Set tags on the VloziClient
This is the simplest approach. Every fetch the client makes inherits the tags automatically:
// lib/vlozi.ts
import { VloziClient } from "@vlozi/blog";
import { VLOZI_BLOG_TAG, vloziPostTag } from "@vlozi/blog/next";
// Module-scope client for server-side use
export const vlozi = new VloziClient({
apiKey: process.env.VLOZI_API_KEY ?? "",
baseUrl: process.env.VLOZI_BASE_URL ?? "",
nextTags: [VLOZI_BLOG_TAG], // tag every fetch this client makes
});For post detail pages, you can add a per-post tag at fetch time:
// app/blog/[slug]/page.tsx
const post = await vlozi.blog.get(params.slug, {
nextTags: [vloziPostTag(params.slug)], // in addition to VLOZI_BLOG_TAG
});Option B — Set tags per-fetch in RSC
import { unstable_cache } from "next/cache";
import { VLOZI_BLOG_TAG, vloziPostTag } from "@vlozi/blog/next";
const getPost = unstable_cache(
(slug: string) => vlozi.blog.get(slug),
["blog-post"],
{ tags: [VLOZI_BLOG_TAG, vloziPostTag("__slug__")] }
);Revalidating
revalidateVloziBlog
Programmatically trigger revalidation from anywhere (API route, server action, webhook handler):
import { revalidateVloziBlog } from "@vlozi/blog/next";
// Revalidate everything (list + all posts)
await revalidateVloziBlog();
// Revalidate just the list (not individual post pages)
await revalidateVloziBlog({ shallow: true });
// Revalidate specific posts by slug
await revalidateVloziBlog({ slugs: ["my-post-slug", "another-post"] });Under the hood, this calls Next.js revalidateTag() using a dynamic import — the SDK never bundles next/cache into client code.
From a Route Handler (webhook)
Create a route handler that Vlozi (or your own code) can call after publishing:
// app/api/revalidate-blog/route.ts
import { NextResponse } from "next/server";
import { revalidateVloziBlog } from "@vlozi/blog/next";
export async function POST(request: Request) {
const { slug } = await request.json().catch(() => ({}));
if (slug) {
await revalidateVloziBlog({ slugs: [slug] });
} else {
await revalidateVloziBlog();
}
return NextResponse.json({ revalidated: true });
}Then after publishing a post in the Vlozi Dashboard, call this endpoint:
curl -X POST https://yoursite.com/api/revalidate-blog \
-H "Content-Type: application/json" \
-d '{"slug": "my-new-post"}'NOTE
A first-party webhook integration (where Vlozi calls your revalidation endpoint automatically on publish) is on the SDK roadmap. Until it ships, the curl/manual approach above is the recommended pattern.
Setting revalidate on pages
If you use time-based revalidation instead of (or in addition to) on-demand revalidation, export revalidate from your page:
// app/blog/[slug]/page.tsx
// Re-generate each post at most once per hour
export const revalidate = 3600;
// Or: always serve the cached version but regenerate in background
export const revalidate = "force-cache";For most blogs, on-demand revalidation is better — pages only rebuild when content actually changes, not on a fixed schedule.
Complete setup example
// lib/vlozi.ts — server-side client with ISR tags
import { VloziClient } from "@vlozi/blog";
import { VLOZI_BLOG_TAG } from "@vlozi/blog/next";
export const vlozi = new VloziClient({
apiKey: process.env.VLOZI_API_KEY ?? "",
baseUrl: process.env.VLOZI_BASE_URL ?? "",
nextTags: [VLOZI_BLOG_TAG],
});// app/blog/[slug]/page.tsx — static + per-post ISR tag
import { generateStaticParamsForPosts, generateMetadataForPost, vloziPostTag } from "@vlozi/blog/next";
import { BlogContent } from "@vlozi/blog/react";
import { vlozi } from "@/lib/vlozi";
import { notFound } from "next/navigation";
export async function generateStaticParams() {
return generateStaticParamsForPosts(vlozi);
}
export async function generateMetadata({ params }: { params: { slug: string } }) {
return generateMetadataForPost(vlozi, params.slug, {
baseUrl: process.env.NEXT_PUBLIC_SITE_URL,
});
}
export default async function BlogPostPage({ params }: { params: { slug: string } }) {
// Per-post ISR tag so revalidateVloziBlog({ slugs: [slug] }) targets only this page
const post = await vlozi.blog.get(params.slug, {
nextTags: [vloziPostTag(params.slug)],
}).catch(() => null);
if (!post) notFound();
return (
<article>
<h1>{post.title}</h1>
{post.content && <BlogContent html={post.content} />}
</article>
);
}// app/api/revalidate-blog/route.ts — on-demand revalidation endpoint
import { NextResponse } from "next/server";
import { revalidateVloziBlog } from "@vlozi/blog/next";
export async function POST(request: Request) {
const { slug } = await request.json().catch(() => ({}));
await slug ? revalidateVloziBlog({ slugs: [slug] }) : revalidateVloziBlog();
return NextResponse.json({ revalidated: true });
}What each tag covers
| Tag | Revalidates |
|---|---|
VLOZI_BLOG_TAG ("vlozi-blog") |
Everything — blog list pages + all post detail pages |
vloziPostTag(slug) ("vlozi-post:<slug>") |
Only the single post detail page for that slug |
| Both tags on a detail page | Revalidates individually (via slug) or globally (via VLOZI_BLOG_TAG) |
Use VLOZI_BLOG_TAG alone for simple setups. Add vloziPostTag per-post when you want surgical revalidation (e.g., editing one post without revalidating all post pages).