Config-Driven SSR

Alloy supports an ssr: config block that pipes rendered HTML through an external command via stdin/stdout:

# alloy.config.yaml
ssr:
  command: "node ssr-worker.js"
  mode: "exec"
  timeout: 10000

With this config, every page containing custom element tags is sent through the configured command for server-side rendering.

Exec vs stream modes

Mode Behavior Best for
exec Spawns a new process for each page Stateless workers, maximum isolation
stream Starts one persistent subprocess, pages piped sequentially Faster builds, shared state between pages

In exec mode, the command starts and stops for every page that contains custom elements. In stream mode, Alloy starts the command once and pipes pages through it one at a time. Stream mode avoids repeated startup costs but requires the worker to handle sequential input correctly.

Timeout

The ssr.timeout value is in milliseconds. If the SSR command does not return output within the timeout, the build fails with an error identifying the page that timed out.

SSR worker example

The SSR command can be any executable that reads HTML from stdin and writes transformed HTML to stdout:

// ssr-worker.js
import { render } from '@lit-labs/ssr';
import { html } from 'lit';

let input = '';
process.stdin.on('data', (chunk) => { input += chunk; });
process.stdin.on('end', async () => {
  const result = await render(input);
  process.stdout.write(result);
});