Spawner
GitHub Install

Preview environments for every branch, on your own server.

Spawner is an open source, self-hosted preview environment manager: a copy of your app for each git branch, built from its Docker Compose file, with its own URLs, database and logs. Developers and coding agents start one with a single command; reviewers open it from a link.

Free and open source (Apache-2.0). One Linux server, no Kubernetes.

Example: four branches of a project named blog, each with its own environment.
  • feat/login Ready feat-login--blog.preview.example.com web, api, db
  • fix/checkout Building from a worktree, 2 uncommitted files Ben via laptop
  • feat/search-filters Ready feat-search-filters--blog.preview.example.com Ada via claude
  • main Sleeping main--blog.preview.example.com wakes up on a visit

4 environments; 9 more fit on this server

A new environment in seconds

From a branch, or straight from your worktree with its uncommitted changes. One command, and the branch has its own URL and database: about 5 s once the project’s images are built.

~/code/shop on feat/login, one file changed

$ spawner up --wait
Packing app: 9 files, 4.9 KiB
Creating feat-login in shop
Job cmuzritro003710o92x7ikd2x queued
preparing...
building...
routing...
Ready in 5s
feat-login (shop) is ready
  web  http://feat-login--shop.localtest.me
Expires in 72h. The URLs need a login; for curl or tests: spawner url feat-login --with-token
$ 
Real time, with Spawner on the same laptop. A new branch reuses the images its project already built (12 s the first time), and the database healthcheck polls every 250 ms while it starts.

How it works

Spawner builds each preview environment (also called an ephemeral environment or a review app) from what the repository already has: its Docker Compose file, plus a short manifest.

  1. Add .spawner/ to the repository

    spawner init writes the manifest, which names the URLs and the seed, and a Docker Compose file to adjust.

  2. Start an environment

    spawner up from a worktree, uncommitted changes included, or a branch from the dashboard. Spawner checks the compose file against its policy, builds and starts it on a network of its own, and runs the seed.

  3. Open it

    Traefik routes <env>--<project>.<domain> with HTTPS, behind your team’s login; guests get a share link. After 2 hours unused it sleeps, and the next visit wakes it up.

version: 1
project: example
exposures:
  - name: web
    service: app
    port: 3000
seed:
  - service: app
    run: [node, seed.js]
ttl: 24h
.spawner/spawner.yaml of the Node.js and PostgreSQL example, next to a regular compose.yaml. Every key is in the manifest reference.

Every branch in one dashboard

Who started each environment, what it uses and when it sleeps. Each one has its logs with an error filter, its CPU and memory over time, a timeline of crashes, and a terminal into any service.

The Environments page of the Spawner dashboard, version 2.2.0: five environments of two projects, owned by Ben, Lina and Ada. Ben's feat-comments is building and his feat-login, started by his coding agent, is ready; Lina's feat-login is asleep; Ada's feat-search, started by her agent, and main are ready. Each row shows its source, its owner, its memory and its lifecycle. The Environments page of the Spawner dashboard, version 2.2.0: five environments of two projects, owned by Ben, Lina and Ada. Ben's feat-comments is building and his feat-login, started by his coding agent, is ready; Lina's feat-login is asleep; Ada's feat-search, started by her agent, and main are ready. Each row shows its source, its owner, its memory and its lifecycle.
Two projects, three people and their coding agents: one environment building, one asleep. Screenshot of a local install. Open it at full size Open it at full size

What Spawner does differently

Previews of work nobody has pushed

spawner up sends the worktree, uncommitted changes included, so a developer or an agent tests a change before pushing it. Branches, tags and commits work too, from the CLI or the dashboard.

spawner up
A CLI and an MCP server for coding agents

Commands print JSON with --json and exit with codes an agent can act on: 4 when the environment failed, 6 when the quota or the capacity is reached, 7 when .spawner/ was refused. spawner mcp gives Claude Code, Codex or Cursor nine tools, from spawner_up to spawner_down.

Set up your agents
One server, no Kubernetes

Docker Compose behind Traefik, on a Linux server of yours. Environments nobody uses for 2 hours sleep, and wake up on the next visit; Spawner measures what they really use and says how many more fit. The Laravel, Next.js and MySQL example runs in about 320 MiB.

Making environments cheap
Checked before it runs, protected once it does

Every compose file goes through an allowlist: no host mounts, privileged containers, host network or Docker socket. Each environment gets its own network, away from the cloud’s metadata and the server’s services, and its URLs need your team’s login; guests get a share link. Branches still run code nobody reviewed: give Spawner a server of its own.

What it protects, and what it leaves to you
Accounts without passwords

Invitations and passkeys, GitHub login if you want it, two roles, tokens with scopes and an expiry, and an audit trail of who did what.

Access

Frequently asked questions

Is it free?

Yes. Spawner is open source under the Apache-2.0 license and runs entirely on your server: there is no hosted service and nothing to sign up for. You pay for the server.

Does it need Kubernetes?

No. It needs one Linux server, dedicated to previews: Ubuntu 22.04 or 24.04, or Debian 12, on amd64 or arm64, with 4 GiB of memory at least (8 GiB or more advised), ports 80 and 443, and a wildcard DNS record such as *.preview.example.com. The installer sets up Docker; each environment is a Docker Compose project behind Traefik. See installing Spawner.

Can I get a preview for each pull request?

Not by itself: Spawner does not watch your git host. A CI job runs spawner up when a pull request opens and spawner down when it closes; the CI guide has the workflows for GitHub Actions and GitLab CI.

Which stacks does it run?

Anything Docker Compose runs: any language, databases as services, and apps spread over several repositories. Two examples are ready to deploy: Node.js and PostgreSQL; Laravel, Next.js and MySQL.

Is it safe to run branches nobody has reviewed?

Spawner checks every compose file against an allowlist (no host mounts, privileged containers, host network or Docker socket), gives each environment its own network, and keeps previews behind your team’s login. Containers cannot reach the cloud’s metadata or the server’s own services, but they share its kernel and reach the internet: use a server dedicated to previews, with test data only. See security.

How do coding agents use it?

With the same CLI as people: spawner up --wait --json from their worktree, then the URL, the logs and commands in the environment, with exit codes they can act on. Or through its MCP server, in Claude Code, Codex, Cursor or any MCP client. spawner init adds the instructions to AGENTS.md or CLAUDE.md. See coding agents.

Does Spawner send data anywhere?

No telemetry: Spawner sends nothing about your server, your projects or your people. Besides what you set up (git hosts, image registries, Let’s Encrypt and your DNS provider, GitHub login), a server makes one request on its own: the list of releases from api.github.com every 6 hours, which SPAWNER_UPDATE_CHECK=false turns off. The CLI talks to your server only (network).

Can it run production, or several servers?

No: one installation runs previews on one server, dedicated to them. What Spawner does not do lists its limits, and the comparison sets it next to other tools.

Install it on your server

Four steps from a fresh server to a first environment. The server: Ubuntu 22.04 or 24.04, or Debian 12, amd64 or arm64, 4 GiB of memory at least (8 GiB or more advised), ports 80 and 443.

  1. Set up the server

    On a Linux server dedicated to previews, with a DNS record such as *.preview.example.com pointing to it. The installer asks for the domain, an e-mail and your DNS provider, sets up Docker, and prints the link that creates the first admin account.

    curl -fsSL https://github.com/Flosk6/Spawner/releases/latest/download/install.sh | sudo bash

    Read the script before running it, or try Spawner in a local VM, without a domain.

  2. Install the CLI and log in

    On your machine, with Node.js 20 or later. Then run spawner login with the dashboard’s address, spawner.preview.example.com for that domain: it opens the dashboard, where you enter the code it shows.

    npm install -g spawner-cli
  3. Add the project

    In the dashboard, an admin opens Projects, then New project: a slug, the repository, and for a monorepo the directory that holds .spawner/.

  4. Start its first environment

    In the project: init writes .spawner/ (add --project with the slug if it is not the directory’s name), up starts the environment of the branch.

    spawner init && spawner up --wait

The quickstart goes through each step. The latest release is Spawner 2.2.1: what changed.