Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
API Endpoints  ›  Lesson

Static vs Dynamic Handlers

Static vs Dynamic 13 minGET route handlers run on every request by default, and you can opt one into being generated once and cached, optionally refreshed on a timer.

Static vs Dynamic Handlers

The phone app calls GET /api/trails every time it opens: thousands of times a day. The trail list changes maybe three times a day. Running the handler and querying the database for every one of those calls repeats the same work to produce the same answer. Pages can be static; so can endpoints.

The rule

Handlers run per request by default; opt a GET into static when everyone gets the same answer.

In current Next.js, a GET route handler is dynamic by default: it runs on every request. That is the safe choice, because a handler might read cookies, headers or the query string.

When a GET handler's answer is the same for everyone, opt it into static with route segment config:

// app/api/trails/route.ts
export const dynamic = "force-static"; // generate once, serve the saved result
export const revalidate = 3600;        // regenerate at most once an hour

export async function GET() {
  const trails = await getTrails();
  return Response.json(trails);
}

Now next build runs the handler, saves the response, and serves that copy to every caller. With revalidate, the saved copy is refreshed in the background once it is older than an hour, just like a static page.

Three rules keep this safe:

  • Only GET can be cached. POST, PUT, PATCH and DELETE change things, so they always run.
  • Request-specific data does not mix with static. Under force-static, reading cookies or headers gives empty values, because there is no real request at build time. A handler that depends on the caller must stay dynamic.
  • Dynamic is the default. You only add config when you decide caching is safe.

Newer releases also offer an opt-in "use cache" directive that expresses the same idea in a different way; the question you ask is identical.

The shortcut

For each endpoint ask "Would every caller get the same bytes?" and "Does it only read?" Two yeses: static, with a revalidate matched to how often the data changes. Any no: leave it dynamic.

Deciding for three Trailhead endpointsStep 1 of 4
  1. GET /api/trails

    Same list for everyone, read-only, changes a few times a day. Static with revalidate = 3600.

The trap is making a handler that reads the session cookie force-static. Nothing errors, but every caller gets the same answer, built from an empty cookie at build time.

Drills

Answer fast — trust the rule.

quick drill

By default in current Next.js, when does a GET route handler run?

quick drill

Which line opts a GET handler into being generated once and reused?

quick drill

Which Trailhead handler can safely be static?

quick drill

With force-static and revalidate = 600, what happens after ten minutes?

Remember

  • Handlers run per request by default; opt a GET into static when everyone gets the same answer.
  • Shortcut: same bytes for every caller, and read-only? Then static with a sensible revalidate.
  • Trap: request-specific handlers must stay dynamic, and non-GET methods are never cached.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainCache it or not?

Trailhead has GET /api/trails (the full list, updated a few times a day), GET /api/me (the signed-in hiker, from a cookie), and POST /api/reviews. Explain which, if any, you would cache and how.