billing hacks

Route Cache (SSG & ISR)

Pre-render pages at build time or on a schedule. Zero runtime cost per view.

TL;DR

Static generation = zero runtime cost. ISR = one function call per revalidation period. Check your build output for ƒ routes that could be ○ or ●.

Next.js can pre-render entire pages and serve them as static HTML.

Static Generation (Best)

// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await getAllPosts();
  return posts.map((post) => ({ slug: post.slug }));
}

export default async function BlogPost({ params }) {
  const post = await getPost(params.slug);
  return <Article post={post} />;
}

Result: Pages built at deploy. Zero cost per view.

ISR (Time-Based)

Re-generate on a schedule:

// app/products/[id]/page.tsx
export const revalidate = 3600; // Every hour

export default async function ProductPage({ params }) {
  const product = await getProduct(params.id);
  return <ProductDetails product={product} />;
}

Result: One function run per hour, regardless of traffic.

On-Demand Revalidation

Regenerate when content changes:

app/api/cms-webhook/route.ts
import { revalidatePath, revalidateTag } from 'next/cache';

export async function POST(request: Request) {
  const { type, slug } = await request.json();

  if (type === 'post.updated') {
    revalidatePath(`/blog/${slug}`);
  }

  if (type === 'author.updated') {
    revalidateTag('authors');
  }

  return Response.json({ revalidated: true });
}

What Breaks Route Cache

These make your page dynamic:

cookies();
headers();
searchParams; // without generateStaticParams
export const dynamic = 'force-dynamic';

A cookies() call anywhere in the component tree makes the entire page dynamic. Even in a utility function.

Check Your Build

npm run build
  • ○ Static - Good
  • ● SSG - Good
  • ƒ Dynamic - Runs every request

Next: Data Cache for caching fetch calls and DB queries.

On this page