skip to content

Static Route Generation

RenderMode.Prerender writes static HTML at build time, with getPrerenderParams listing the paths of parameterized routes and a fallback for the rest. Interviewers ask what cannot be prerendered.

part ofAngularoverview, primer and where to startread it →
on this pageshow

explore

questions

5

In an Angular app using @angular/ssr, how do you mark a route for build-time prerendering, and what does the build produce for it?

level: juniorimportance: must knowfreq 52%

answer

  1. server routes file
  2. RenderMode enum value
  3. one HTML file per path
  4. default catch-all route

basics

~10 s

Give the route RenderMode.Prerender in the server routes passed to provideServerRendering(withRoutes(...)). At build time Angular renders it once and writes a static index.html for that path, which is served as-is to every visitor.

solid answer

~40 s

Render modes live in the server routes array, usually `app.routes.server.ts`, registered with `provideServerRendering(withRoutes(serverRoutes))` from `@angular/ssr`. An entry `{ path: 'pricing', renderMode: RenderMode.Prerender }` tells `ng build` to boot the app for that path at build time, wait until it is stable, and write the HTML to the browser output folder as `pricing/index.html`. Every visitor then gets that same file, served by Angular's server engine (with an `ETag`) or by any static host. The CLI's SSR schematic starts with a single `{ path: '**', renderMode: RenderMode.Prerender }`, so every route without parameters is prerendered by default. Routes with parameters need `getPrerenderParams` to list their paths. Because the render happens at build time, there is no request: nothing user-specific, and no per-route `status`.

go deeper

for a junior

Remember that RenderMode.Prerender goes in the server routes file and makes the build write one static HTML file per path.

for a middle

Explain the build steps, how the file is served, the default catch-all Prerender route, and why parameterized routes need getPrerenderParams.

for a senior

Judge which routes suit build-time rendering by asking what each page depends on at request time and how fresh its data must be.

for a principal

Weigh build duration and deploy size against serving cost when deciding how much of a large site to prerender.

## Where the setting lives An Angular app with server rendering has two route lists: - the **client routes** in `app.routes.ts`, used by the Angular router; - the **server routes** in `app.routes.server.ts`, a `ServerRoute[]` that tells `@angular/ssr` how to render each path. The server routes are registered in the server config: ```ts // app.config.server.ts import { ApplicationConfig, mergeApplicationConfig } from '@angular/core'; import { provideServerRendering, withRoutes } from '@angular/ssr'; import { appConfig } from './app.config'; import { serverRoutes } from './app.routes.server'; const serverConfig: ApplicationConfig = { providers: [provideServerRendering(withRoutes(serverRoutes))], }; export const config = mergeApplicationConfig(appConfig, serverConfig); ``` Each server route picks one `RenderMode`: `Server` (render per request), `Client` (send the client-side shell) or `Prerender`, which is the subject here. ## What RenderMode.Prerender does For a route marked `RenderMode.Prerender`, the build does the rendering work ahead of time: 1. `ng build` extracts the application's routes and matches each against the server routes. 2. For every prerendered path, it bootstraps the app on the server, navigates to the path and waits until the application is stable. 3. It serializes the result, including any transferred state, into HTML. 4. It writes the file to the browser output folder as `<path>/index.html`, for example `pricing/index.html`. At runtime: - With Angular's server engine, the matching file is returned for `GET` and `HEAD` requests with an `ETag`, and a matching `If-None-Match` gets a `304`. The route's `headers` are added to the response. - With no server at all (the build's static output mode), any static file host can serve the files directly. ## The default: everything is prerendered The CLI schematic that adds SSR generates this server routes file: ```ts import { RenderMode, ServerRoute } from '@angular/ssr'; export const serverRoutes: ServerRoute[] = [ { path: '**', renderMode: RenderMode.Prerender }, ]; ``` So in a freshly generated app every client route is prerendered. That works for routes without parameters. A route with a parameter such as `docs/:slug` has no single path to render, so it needs a `getPrerenderParams` function that lists the concrete values; without one the build fails. ## What a prerendered page cannot know Prerendering happens once, at build time, for everyone: | Question | Prerendered answer | |---|---| | Who is the visitor? | Unknown: the `REQUEST` token is `null` during static generation | | Which cookies or headers were sent? | None | | Which query string was used? | The file is chosen by path; the query string does not select a different file | | Which HTTP status should be sent? | Not configurable: prerender server routes have no `status` property | | Is the data current? | As current as the last build | Pages that are the same for every visitor (marketing pages, documentation, blog posts) fit well. Pages whose content depends on the visitor or the request belong on `RenderMode.Server` or `RenderMode.Client`. ## A worked example A small documentation site might configure its server routes like this: ```ts import { RenderMode, ServerRoute } from '@angular/ssr'; export const serverRoutes: ServerRoute[] = [ { path: '', renderMode: RenderMode.Prerender }, // landing page { path: 'pricing', renderMode: RenderMode.Prerender }, // same for everyone { path: 'account/**', renderMode: RenderMode.Server }, // depends on the visitor { path: '**', renderMode: RenderMode.Prerender }, // everything else ]; ``` The build writes `index.html` and `pricing/index.html`; account pages are rendered per request because they depend on who is asking. Documentation pages with a `:slug` parameter would additionally need `getPrerenderParams`. ## Costs to keep in mind - **Build time and output size** grow with the number of prerendered paths. - **Code must be server-safe**, exactly as for per-request rendering, because the same server platform renders it. - **Data sources must be reachable during the build**, since components fetch their data at build time. ## Why interviewers ask it It checks whether a candidate knows where Angular's render modes are configured, what the generated default does, and the boundary of what a build-time render can contain.

  • Why can't you set a status code on a prerendered server route?
    The status belongs to a response, and a prerendered page is a file written at build time, served identically to everyone. The `ServerRoute` type for prerendering omits `status`, while still allowing `headers`, which Angular's server engine adds when it serves the file.
  • Does a prerendered page still hydrate and become interactive?
    Yes. The file contains the rendered HTML plus the application's scripts, and any transferred state. The browser boots the app and hydrates the prerendered DOM the same way it hydrates a page rendered per request.

saying these in an interview costs you the question

  • Prerendered pages are rendered on the first request and then cached.
  • RenderMode.Prerender is set on the client route in app.routes.ts.
  • A prerendered page can read the visitor's cookies through REQUEST.
  • Prerendered pages are static HTML with no Angular app running afterwards.
  • Routes with parameters are prerendered automatically for every value.
open as a page

An Angular SSR build fails after adding a docs/:slug route; why, and how does getPrerenderParams let you prerender each documentation page?

level: middleimportance: must knowfreq 48%

basics

~20 s

The default '**' Prerender server route now matches docs/:slug, and the build cannot guess slug values, so it fails. Add a server route for docs/:slug with getPrerenderParams returning objects like { slug: 'routing' }; the build renders one page per object.

open as a page

In Angular SSR, what happens when a visitor requests a docs page that getPrerenderParams did not list, and how do PrerenderFallback.Server, Client and None differ?

level: middleimportance: should knowfreq 34%

basics

~20 s

The route's fallback decides. PrerenderFallback.Server, the default, renders the page on the server at request time; Client sends the client-rendered shell; None makes Angular's engine decline the request, so the next handler, usually a 404, answers.

open as a page

Which Angular routes should not use RenderMode.Prerender, and what goes wrong when a request-dependent page is prerendered?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Pages that depend on the visitor, cookies, headers, query strings or fast-changing data should not be prerendered. At build time REQUEST is null, so the page renders its anonymous, default version once, and every visitor receives it until the next build.

open as a page

How does Angular deliver a route with redirectTo when the app is prerendered for static hosting, compared with when Angular's server engine serves it?

level: middleimportance: nice to knowfreq 20%

basics

~20 s

With static output, the build writes an HTML page for the old path containing a zero-delay meta refresh and a link: a soft redirect served with status 200. Behind Angular's server engine, the same route gets a real HTTP redirect, 302 by default.

open as a page