In production, how do you build, start, health-check and restart Inertia's SSR server with Artisan, and what does --runtime change?
answer
- vite build plus vite build --ssr
- bundle in bootstrap/ssr
- inertia:start-ssr under a process monitor
- stop-ssr on deploy, --graceful
- check-ssr hits /health
basics
~20 sBuild the client and SSR bundles, run php artisan inertia:start-ssr under a process monitor, verify it with inertia:check-ssr, and on each deploy run inertia:stop-ssr so the monitor restarts it on the new bundle; --runtime picks node, bun or a binary path.
solid answer
~40 sProduction SSR needs two builds, `vite build && vite build --ssr` (the starter kits' `build:ssr` script), which writes the server bundle under `bootstrap/ssr`. `php artisan inertia:start-ssr` finds that bundle (or `inertia.ssr.bundle`), first calls `inertia:stop-ssr` silently, and then runs it with the runtime from `--runtime` or `inertia.ssr.runtime` (`INERTIA_SSR_RUNTIME`, default `node`); `bun` or an absolute binary path also work, and `ensure_runtime_exists` makes a missing binary fail fast. Because the command stays in the foreground, you run it under Supervisor or a similar monitor. On deploy, `inertia:stop-ssr` calls the server's `/shutdown` endpoint and the monitor restarts it with the new bundle; `--graceful` exits 0 when nothing was running. `inertia:check-ssr` calls `/health` and exits non-zero on failure, which suits a container health check.
code
bash · 8 lines# build both bundles
npm run build:ssr
# during the deploy: stop the old renderer; the process monitor restarts it
php artisan inertia:stop-ssr --graceful
# after the restart: fail the pipeline if SSR is not answering
php artisan inertia:check-ssrgo deeper
Know that production SSR needs an extra build and a running process started with php artisan inertia:start-ssr.
Explain bundle detection, the runtime option and its default, the port, and what stop-ssr, --graceful and check-ssr each do.
Fit SSR into deploys and infrastructure: process monitors, restart on release, health checks, timeouts and containers without the bundle file.
Decide how the SSR runtime is hosted and scaled, alongside the app or as its own service, and who owns its uptime and upgrades.
## Two bundles, one extra process An **Inertia** app with server-side rendering ships two JavaScript builds: - the **client bundle** in `public/build`, served to browsers; - the **SSR bundle** in `bootstrap/ssr`, run by a long-lived Node or Bun process that renders page components to HTML. The usual build is `vite build && vite build --ssr`; the React and Vue starter kits expose it as `npm run build:ssr`. With the `@inertiajs/vite` plugin the SSR entry is detected automatically (a `resources/js/ssr.*` file if present, otherwise the `app.*` entry is reused). In development none of this is needed: Inertia 3 renders through the Vite dev server. The commands below are for production. ## Starting the server `php artisan inertia:start-ssr` does the following: 1. refuses to run if `inertia.ssr.enabled` is false; 2. locates the bundle: `inertia.ssr.bundle` if set, otherwise the first existing file among `bootstrap/ssr/ssr.js`, `bootstrap/ssr/app.js`, their `.mjs` variants and two legacy `public/js` paths; 3. picks the **runtime**: the `--runtime` option, else `inertia.ssr.runtime` (env `INERTIA_SSR_RUNTIME`, default `node`); 4. if `ensure_runtime_exists` is true, fails when that binary cannot be found; 5. silently runs `inertia:stop-ssr` to clear an old instance; 6. starts `<runtime> <bundle>` with no timeout and streams its output, reporting stderr lines as exceptions. The server listens on port **13714** by default. Laravel reaches it at `inertia.ssr.url` (default `http://127.0.0.1:13714`). The bundle can enable Node's **cluster** mode to fork one worker per CPU on the same port. | `--runtime` value | Effect | |---|---| | omitted | uses `inertia.ssr.runtime`, `node` by default | | `bun` | runs the bundle with Bun | | `/usr/local/bin/node22` | runs a specific binary by absolute path | The docs require Node.js 22 or newer for the SSR server. ## Keeping it running `inertia:start-ssr` stays in the foreground, so production runs it under a **process monitor** such as Supervisor, systemd or the platform's daemon feature, configured to restart it when it exits. With the `pcntl` extension loaded, the command traps `SIGINT`, `SIGQUIT` and `SIGTERM` and stops the Node process it started, so the monitor can shut both down cleanly. ## Restarting on deploy The SSR process loads the bundle once. After a deploy that ships new page components, an old process would keep rendering old code, or fail to find new pages. So the deploy runs: - `php artisan inertia:stop-ssr`: sends a request to the server's `/shutdown` endpoint; the process exits and the monitor starts a fresh one on the new bundle; - `php artisan inertia:stop-ssr --graceful`: the same, but exits successfully when no server is running, which keeps first deploys and scripted pipelines green. ## Checking health `php artisan inertia:check-ssr` sends a GET to `/health` through the same HTTP client settings as rendering (including `inertia.ssr.timeout` and any `Inertia::configureSsrRequestUsing()` callback). It prints whether the server is running and exits non-zero when it is not, so it works as a container health check or a post-deploy smoke test. ## Multi-server and container setups - If web containers do not carry the SSR bundle file, set `inertia.ssr.ensure_bundle_exists` to false, otherwise the gateway skips SSR because it cannot see the bundle. - Point `INERTIA_SSR_URL` at the SSR service's address when it runs on another host. - Set `INERTIA_SSR_TIMEOUT` so a hung SSR server delays responses briefly and then falls back to client rendering. ## Common mistakes - building only the client bundle, so `start-ssr` reports the bundle missing; - deploying without `stop-ssr`, leaving a stale renderer; - running `start-ssr` in a shell with no monitor, so the first crash ends SSR for good.
- Why is inertia:stop-ssr enough to load a new bundle?The command asks the running server to shut down through its `/shutdown` endpoint. The process monitor sees the exit and runs `inertia:start-ssr` again, which starts a new process that reads the freshly built bundle.
- When would you set ensure_bundle_exists to false?When the web servers that run Laravel do not have the SSR bundle on disk, for example a separate SSR container. Otherwise the gateway checks for the file, finds nothing and quietly renders client-side only.
saying these in an interview costs you the question
- inertia:start-ssr daemonises itself, so no process monitor is needed
- A deploy picks up the new SSR bundle without restarting the process
- --runtime selects between the React and Vue renderers
- inertia:check-ssr rebuilds the SSR bundle when it is missing
- The SSR server must run during local development too