Manual contentsCLI ReferenceBrowse 103 chapters
Manual 5 min read

suprnova serve

suprnova serve runs your backend and the Vite dev server together with hot reload on both sides, plus automatic TypeScript type regeneration whenever you touch a #[derive(InertiaProps)] struct. It's the one command you keep open in a terminal while you're building.

suprnova serve

Both processes stream their stdout into the same terminal with coloured [backend] and [frontend] prefixes so you can tell who said what. Ctrl+C shuts them both down cleanly.

Usage

suprnova serve [OPTIONS]
Option Default Description
-p, --port <PORT> 8765 (CLI) / $SERVER_PORT (env) Backend HTTP port
--frontend-port <PORT> 5765 (CLI) / $VITE_PORT (env) Vite dev server port
--backend-only false Skip the Vite dev server
--frontend-only false Skip the backend, just run Vite
--skip-types false Don't regenerate TypeScript types on Rust changes

The CLI flags take precedence over environment variables, which take precedence over the built-in defaults. A scaffolded .env ships with SERVER_PORT=8765 and VITE_PORT=5765; you'll see those values used unless you override with --port.

Examples

Default - both servers

suprnova serve

Output:

Backend  http://127.0.0.1:8765
Frontend http://127.0.0.1:5765
[backend] Compiling my-app v0.1.0 ...
[frontend] VITE v6.3.0  ready in 312 ms

Hit http://127.0.0.1:8765 in your browser. The backend serves the Inertia HTML shell and proxies asset requests through to Vite, so you don't need to visit the Vite URL directly.

Custom ports

suprnova serve --port 3000 --frontend-port 3001

Or set them in .env and run without flags:

SERVER_PORT=3000
VITE_PORT=3001

Backend only

suprnova serve --backend-only

Good for working on an API-only project, or when your frontend is already running in another terminal (or another machine, or a deployed preview).

Frontend only

suprnova serve --frontend-only

Good for working on UI without paying the cost of a Rust rebuild on every save, or when the backend is running in another shell (or in Docker).

Skip type generation

suprnova serve --skip-types

Disables the TypeScript regeneration watcher. Use this when you're managing frontend/src/types/inertia-props.ts by hand, or when you're working far from any Inertia code and want quieter output.

What it actually does

When you run suprnova serve, the CLI:

  1. Loads .env from the current directory.
  2. Resolves backend and frontend ports (CLI flag → env var → default).
  3. Verifies you're in a Suprnova project - Cargo.toml must exist (unless --frontend-only) and a frontend/ directory must exist (unless --backend-only).
  4. Regenerates TypeScript types from any #[derive(InertiaProps)] structs it finds in src/, writing them to frontend/src/types/inertia-props.ts.
  5. Installs cargo-watch via cargo install --locked --version "^8.5" cargo-watch if it isn't on the PATH yet (one-time, with an "Installing..." notice). Skipped under --frontend-only. The version is bounded because serve drives cargo watch -x, whose meaning is not guaranteed across a major bump; --locked builds the dependency tree cargo-watch published rather than re-resolving it at install time. A command that installs software as a side effect of starting a dev server should not also be choosing versions for you.
  6. Runs npm install in frontend/ if node_modules doesn't exist yet. Skipped under --backend-only.
  7. Spawns cargo watch -x 'run --bin <package-name>' for the backend. cargo-watch re-runs the binary whenever a .rs file changes.
  8. Spawns npm run dev in frontend/ for Vite, which gives you HMR for Svelte/React/Vue components and Tailwind classes.
  9. Starts a file watcher on src/ that re-runs the type generator whenever a .rs file changes, once the burst of saves has been quiet for 500 ms. The debounce is trailing-edge, so a burst - cargo fmt, format-on-save across several files, a branch switch - coalesces into exactly one regeneration that runs after the last write, rather than one that fires on the first file and misses the rest.
  10. Forwards both children's stdout/stderr to your terminal with [backend] and [frontend] prefixes.

Ctrl+C signals the manager to set its shutdown flag, kill both children, and exit. If either process exits on its own - usually because of a Rust compile error too severe for cargo watch to recover, or a port conflict - the manager treats that as a shutdown signal and tears down the other.

Why Suprnova diverges

Laravel users typically run php artisan serve for the backend and npm run dev in another terminal, and most teams paper over the two-terminal split with a Procfile and foreman/overmind. Suprnova ships that multiplexer as a first-class CLI command. You get one terminal, one Ctrl+C, automatic toolchain bootstrap (cargo-watch, npm install), and a typed-Inertia bridge that regenerates frontend/src/types/inertia-props.ts on the fly so your Svelte/React/Vue components always see the current prop shape without manual type sync.

Hot reload

Backend. cargo watch -x 'run --bin <package>' is the loop. It rebuilds and restarts the server on every .rs change in the project. Cold rebuilds after touching a heavy crate can take several seconds; incremental changes in a single file are usually sub-second.

Frontend. Vite's HMR injects component changes in place without a full reload, preserving component state. Tailwind classes update live via the Tailwind v4 watcher.

TypeScript types. Whenever a .rs file changes, the type watcher re-runs the generator. If new #[derive(InertiaProps)] structs appear (or existing ones change shape), the regenerated frontend/src/types/inertia-props.ts triggers Vite's HMR for the component that imports them.

Troubleshooting

Port already in use

[backend] Error: Address already in use (os error 98)

Find and kill the process, or pick another port:

lsof -i :8765
kill -9 <pid>

# or
suprnova serve --port 8081

cargo-watch install fails

The CLI runs cargo install cargo-watch if it isn't already on PATH. If that install fails (no network, restricted environment), install it manually once:

cargo install cargo-watch

After that, suprnova serve will find it and won't try to install again.

Frontend dependencies stuck

If npm install fails mid-bootstrap, fix the cause (npm registry reachable, disk space, lockfile in good shape) and run it manually:

cd frontend && npm install

Then re-run suprnova serve. The CLI only auto-runs npm install when node_modules is missing, so a successful manual install lets it skip that step.

Type regeneration not picking up changes

The watcher polls every 2 seconds (using notify with a poll interval - chosen for cross-platform reliability over inotify quirks) and debounces regeneration to once every 500 ms. If a change isn't showing up:

  • Confirm the file is under src/ (the watcher doesn't recurse into crates/, cmd/, or migrations/).
  • Confirm the struct actually has #[derive(InertiaProps)].
  • Restart suprnova serve and watch for the Generated N type(s) startup message - if you see No InertiaProps structs found, the scanner didn't find anything to emit.

Backend exits silently right after start

When either child process exits, the manager shuts the other down too. If the backend died with a compile error, the [backend] lines just above the "Servers stopped." message will show the error[E…] from rustc. Fix the compile error and re-run.

Next