skip to content

In an Angular CLI 22 application build, what does `outputMode: 'static'` versus `'server'` change in what `ng build` produces and how you deploy it?

level: middleimportance: should knowfreq 45%

answer

  1. a server bundle or none
  2. browser and server folders
  3. server.mjs run with node
  4. prerender option ignored once set

basics

~20 s

outputMode 'server' emits a browser folder plus a server folder with server.mjs that you run under Node; it needs the server and ssr.entry options. outputMode 'static' emits only browser files, prerendered where possible, for any static host.

solid answer

~40 s

`outputMode` on `@angular/build:application` picks the deployment artifact. With `"server"`, `ng build` writes `dist/<app>/browser` and `dist/<app>/server`, whose `server.mjs` you start with Node; the builder requires both the `server` option (the server entry such as `src/main.server.ts`) and `ssr.entry` (the HTTP server file, `src/server.ts`), and throws if either is missing. `ng add @angular/ssr` sets this up and adds a `serve:ssr:<app>` script running `node dist/<app>/server/server.mjs`. With `"static"`, no server output is written: if a server entry exists, routes are prerendered into HTML at build time, and everything deploys to a static host. Once `outputMode` is set, the older `prerender` and `appShell` options are ignored with a warning; which routes render how is decided by server routes.

code

json · 11 lines
json
{
  "build": {
    "builder": "@angular/build:application",
    "options": {
      "browser": "src/main.ts",
      "server": "src/main.server.ts",
      "outputMode": "server",
      "ssr": { "entry": "src/server.ts" }
    }
  }
}

go deeper

for a junior

Recall that server output needs a Node process and static output only needs a file host, and where each lands under dist.

for a middle

Explain the required server and ssr.entry options, the ignored prerender and appShell options, and the index.csr.html file.

for a senior

Show deployment judgement: keeping browser and server together, the PORT variable, and switching modes without breaking server-rendered routes.

for a principal

Weigh a static site against a Node server for a product: hosting cost, operational load, and which pages truly need request-time rendering.

## What the option chooses `outputMode` is an option of the `@angular/build:application` builder that decides **what kind of artifact** `ng build` produces: | `outputMode` | Output | Needs at runtime | |---|---|---| | `"server"` | `browser/` plus `server/` with `server.mjs` | a Node.js process (or another runtime for the server bundle) | | `"static"` | `browser/` only, with prerendered HTML where available | any static file host | The schema describes `static` as "a static site build artifact for deployment on any static hosting service" and `server` as "a server application build artifact, required for applications using hybrid rendering or APIs". By default the output goes to `dist/<project>/`, with subfolders set by `outputPath`: `browser` and `server` by default, and `media` (fonts and images referenced from CSS) inside the browser folder. ## `outputMode: "server"` This is what `ng add @angular/ssr` (or `ng new --ssr`) configures. The schematic sets: - `outputMode: "server"`; - `ssr: { "entry": "src/server.ts" }`, the HTTP server file (a Node.js server in the generated template); - `security.allowedHosts: []`, the list of host names allowed to access the server-side application; - the `server` option pointing at the server bootstrap file, `src/main.server.ts`; - an npm script `serve:ssr:<project>` that runs `node dist/<project>/server/server.mjs`. The builder validates this mode strictly: without `server` it throws *The "server" option is required when "outputMode" is set to "server"*, and with `ssr` as a plain boolean or without an entry it throws the matching `ssr.entry` error. Deploying means copying the whole `dist/<project>` folder, keeping `browser` and `server` side by side, because the generated server serves static files from the sibling `browser` folder. The generated server listens on the `PORT` environment variable, or `4000` if it is not set. `ssr.platform` defaults to `node`; `neutral` builds a platform-neutral server bundle for edge or serverless runtimes, without Node.js polyfills. ## `outputMode: "static"` With `static`, the builder writes **no server output**. If the project has a server entry, the builder still runs the app at build time to **prerender** routes into HTML files inside `browser/`; without one, you get a classic client-rendered app. Either way the result is plain files that any static host can serve. Because nothing runs at request time, anything that needs per-request rendering must be client-rendered, and the host still needs a fallback for client-side routes that were not prerendered, pointing at the client-rendered shell the build emits (`index.csr.html` when prerendering is on). ## What changes when `outputMode` is set 1. **`prerender` is ignored** with a warning, and prerendering is enabled whenever a `server` entry exists. 2. **`appShell` is ignored** with a warning; an app shell is configured with `withAppShell()` in `provideServerRendering()` instead. 3. **The index file** is written as `index.csr.html` when SSR or prerendering is active, so a host that serves `index.html` automatically does not bypass the server; prerendered routes get their own HTML. Which route is server-rendered, prerendered or client-rendered is not an `angular.json` setting in this model: it lives in the app's server routes (`RenderMode.Server`, `RenderMode.Prerender`, `RenderMode.Client`), which belong to the SSR render-modes topic. ## Checking the output locally 1. Run `ng build` and look at `dist/<project>`: a `server` folder should exist only in server mode. 2. For a server build, run `node dist/<project>/server/server.mjs` and open `http://localhost:4000`; viewing the page source should show rendered HTML, not an empty root element. 3. For a static build, serve `dist/<project>/browser` with any static file server and check that prerendered routes load as their own HTML files. 4. Check the build log for warnings about ignored `prerender` or `appShell` options left over from an older configuration. ## Choosing between them - Choose **`static`** when every page can be built ahead of time or rendered on the client, and you want the cheapest, simplest hosting. - Choose **`server`** when some routes need request-time rendering, you serve API endpoints from the same server, or you rely on server-side redirects. - Moving from `server` to `static` is a one-line change, but check that no route depends on `RenderMode.Server`.

  • You set `"prerender": false` in a project that also sets `outputMode`, yet routes are still prerendered; why?
    When `outputMode` is set, the builder ignores `prerender`, logs a warning, and enables prerendering whenever a `server` entry exists. To keep a route from being prerendered, change its render mode in the server routes rather than the build option.
  • Why does an SSR build write `index.csr.html` instead of `index.html`?
    Many hosts serve a file named `index.html` automatically if it exists, which would bypass the server for `/`. Naming the client-rendered fallback `index.csr.html` keeps requests flowing to the server, which renders or serves prerendered HTML as the route requires.

saying these in an interview costs you the question

  • outputMode static still writes a server bundle you can ignore.
  • The prerender option still controls prerendering when outputMode is set.
  • You can deploy only the server folder of a server build.
  • outputMode server works with ssr set to true and no entry.
  • Per-route rendering choices are made with angular.json flags.