Skip to content
UT Studio
DocumentationNext.jsPerformance

Next.js in these templates

The App Router conventions every template follows, and why so little of it is a client component.

UT Studio7 min read

Every template in the catalogue is built on the Next.js App Router with React Server Components as the default. This page describes the conventions they share, so that the second template you open needs no re-learning.

Server by default, client at the edges

A component is a Server Component unless it needs state, an effect or a browser API. In practice that means the vast majority of a template — every heading, list, table, card and layout — never reaches the browser as JavaScript at all.

The parts that do are small and specific: a theme switcher, a cart, a mobile menu. Each is an island with its own `use client` boundary, and each takes its data as props rather than importing the content layer, so choosing a licence tier does not ship the catalogue to the browser.

State that belongs in the URL

Filtering, sorting, search and pagination are query parameters read on the server. That is a design decision with four consequences worth stating, because they are the reason it is worth the discipline:

  • A filtered view is shareable. Someone can send a colleague exactly what they are looking at.
  • The back button works, because every filter change is a navigation.
  • Reload restores the view instead of resetting it.
  • The cost of interacting does not grow with the size of the catalogue, because nothing re-renders on the client.
app/products/page.tsx
export default async function Page({
  searchParams,
}: {
  searchParams: Promise<Record<string, string | string[] | undefined>>;
}) {
  const filters = parseFilters(await searchParams);
  const result = queryCatalog(filters);

  return <Grid products={result.products} />;
}

Rendering strategies

StrategyUsed forWhy
StaticMarketing pages, docs, articlesContent ships with the deploy; nothing to compute per request
SSG with paramsProduct detail pagesKnown set of routes, prerendered at build
DynamicAnything reading search params or a sessionThe output genuinely differs per request

A page that reads searchParams is dynamic

That is correct, not a mistake — it must be, to answer with the right filter. Prerendering the unfiltered view of such a page is a caching decision, not a rendering one.

Metadata

Every route exports metadata derived from its content rather than written twice. Titles, descriptions, canonicals and OpenGraph images all come from one builder, so a page cannot end up with a canonical that disagrees with its own URL.

Templates with the most application surface

Templates mentioned here

Everything above is written against real products. These are the ones this page draws on.

Read next