> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fly.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Services

A Sprite pauses when nothing is using it, and processes don't reliably survive the trip. A warm wake resumes them where they left off; a cold boot drops them entirely. Anything you started by hand in a shell, a dev server, a database, an agent, is gone after a cold wake unless something brings it back.

That something is a service. A service is a process the Sprite runtime owns: it starts when the Sprite boots, restarts if it crashes, and can receive the HTTP traffic that hits your Sprite's URL. You define it once. The runtime keeps bringing it back.

## Services and the Sprite lifecycle

What happens to a service depends on how the Sprite went down and how it came back:

* **Warm wake.** The VM was suspended with your process inside it. The process resumes mid-thought; it is not restarted. Wakes take 100–500ms.
* **Cold boot.** Process state was dropped. The runtime starts every service fresh, in dependency order. Wakes take 1–2s.
* **Crash.** A service process that exits on its own gets restarted by the runtime.
* **Stop.** A service you stop explicitly stays stopped until you start it again.

Services don't keep a Sprite from pausing. A Sprite with ten services defined still pauses when it goes idle; the services come back on the next wake. A service that's actively handling HTTP requests counts as activity, the same as any other traffic, but a quiet one doesn't hold the Sprite in an active state. If you need a Sprite to stay up while work finishes, that's a job for the [Tasks API](/sprites/keeping-sprites-running), not a service.

## Create a service

The `sprite-env` CLI ships in every Sprite and talks to the runtime's management socket. Create a service with a name, a command, and its arguments:

```bash theme={null}
sprite-env services create web --cmd python3 --args "-m,http.server,3000" --http-port 3000
```

`--cmd` takes the binary only. Arguments go in `--args`, comma-separated.

The command starts the service and streams its first few seconds of output as NDJSON, so a service that dies on startup fails in front of you instead of silently in the background:

```json theme={null}
{"type":"started","timestamp":1780420274555}
{"type":"complete","log_files":{"combined":"/.sprite/logs/services/web.log","stderr":"/.sprite/logs/services/web.log","stdout":"/.sprite/logs/services/web.log"},"timestamp":1780420276551}
```

The stream watches for 5 seconds by default. Pass `--duration 30s` to watch longer, or `--no-stream` to return immediately.

Confirm it's serving:

```bash theme={null}
curl localhost:3000
```

### Create options

| Flag                 | What it does                                                                        |
| -------------------- | ----------------------------------------------------------------------------------- |
| `--cmd <path>`       | The executable to run. Required. Binary only, no arguments here.                    |
| `--args <a,b,c>`     | Comma-separated arguments: `--args "-m,http.server,3000"`                           |
| `--env <K=v,...>`    | Comma-separated environment variables: `--env "PORT=3000,DEBUG=1"`                  |
| `--dir <path>`       | Working directory for the process                                                   |
| `--needs <svc,...>`  | Services that must start before this one                                            |
| `--http-port <port>` | Route the Sprite's URL to this port and auto-start the service on incoming requests |
| `--duration <time>`  | How long to stream logs after starting (default: `5s`)                              |
| `--no-stream`        | Don't stream logs after creation                                                    |

## Serving HTTP

Every Sprite has a URL, and the Sprite's proxy routes incoming requests to port 8080 by default. A service created with `--http-port` changes that:

* Requests to the Sprite's URL route to the service's port instead of 8080.
* If the service isn't running when a request arrives, the proxy starts it first, then forwards the request.
* Only one service can have an HTTP port. Creating a second one fails with `409: another service already has an HTTP port configured`.

Combined with wake-on-request, this gives you a server that costs nothing while idle. A request to a cold Sprite wakes the VM (1–2s), the proxy starts your service, and the request gets served. No traffic, no compute bill.

```bash theme={null}
sprite-env services create web --cmd python3 --args "-m,http.server,3000" --http-port 3000
```

The Sprite's URL requires authentication by default. See [Working with Sprites](/sprites/working-with-sprites#networking-urls-and-port-forwarding) for URL auth modes and testing from outside the Sprite.

<Warning>
  **HTTP services can become public**

  A Sprite URL can be switched to public access. Treat every HTTP service as potentially internet-facing: don't serve secrets, environment variables, or unrestricted filesystem access.
</Warning>

## Managing services

```bash theme={null}
sprite-env services list             # all services and their state
sprite-env services get web          # one service
sprite-env services restart web      # stop, then start; streams logs
sprite-env services stop web         # stop; stays stopped
sprite-env services start web        # start a stopped service
sprite-env services signal web HUP   # send any Unix signal
sprite-env services delete web       # remove the service
```

`get` returns the definition plus live state:

```json theme={null}
{
  "name": "web",
  "cmd": "python3",
  "args": ["-m", "http.server", "3000"],
  "http_port": 3000,
  "state": {
    "name": "web",
    "status": "running",
    "pid": 7353,
    "started_at": "2026-06-02T17:11:14.555839485Z"
  }
}
```

Three behaviors worth knowing:

* **`stop` is sticky.** A stopped service stays stopped. The runtime won't restart it behind your back.
* **Killing the process is not.** Send `TERM` or `KILL` via `signal`, or kill the PID directly, and the runtime treats it as a crash and restarts the service. The state's `restart_count` increments each time. This means `signal web TERM` is effectively a restart; for clarity, use `restart` instead.
* **`delete` removes the definition, not the logs.** The log file stays in `/.sprite/logs/services/` after the service is gone.

## Logs

Everything a service writes to stdout or stderr lands in `/.sprite/logs/services/<name>.log`, timestamped and tagged with the stream it came from:

```text theme={null}
2026-06-02T17:11:17.821Z [stderr] 127.0.0.1 - - [02/Jun/2026 17:11:17] "GET / HTTP/1.1" 200 -
```

Follow it like any other file:

```bash theme={null}
tail -f /.sprite/logs/services/web.log
```

To watch output live while a service starts, use `--duration` on `create`, `start`, or `restart`.

There is no `journalctl` here. Sprites don't run systemd; the log files and the create/start streams are how you see service output.

## Dependencies

A service with `--needs` starts after the services it names. Use it when one process can't come up until another is ready:

```bash theme={null}
# The database starts first
sprite-env services create postgres \
  --cmd /usr/lib/postgresql/16/bin/postgres \
  --args "-D,/home/sprite/pgdata"

# The app starts after postgres
sprite-env services create app \
  --cmd npm --args "start" \
  --dir /home/sprite/myapp \
  --needs postgres
```

On a cold boot, the runtime starts `postgres` before `app`, every time.

## Services, sessions, or tasks?

There are three ways to run something in a Sprite, and they solve different problems:

|                                     | Service                     | Session (`sprite exec`)             | Task                                                    |
| ----------------------------------- | --------------------------- | ----------------------------------- | ------------------------------------------------------- |
| Survives a cold boot                | Yes, restarts automatically | No                                  | No, it's a hold, not a process                          |
| Keeps the Sprite in an active state | Only while handling traffic | Yes, while producing output         | Yes, until it expires                                   |
| Best for                            | Servers, databases, daemons | Interactive work, builds, debugging | Holding the Sprite up while an agent or worker finishes |

They compose. A common pattern for background agents: a service launches the agent at boot, the agent registers a task while it works, the task expires when the work is done, and the Sprite pauses until something needs it again. See [Keeping a Sprite Running](/sprites/keeping-sprites-running) for the task side of that pattern.

## Troubleshooting

**The service died immediately.**

The create stream tells you, with an `exit` event:

```json theme={null}
{"type":"started","timestamp":1780420024883}
{"type":"exit","exit_code":1,"timestamp":1780420025035}
```

Check the log file for the reason:

```bash theme={null}
cat /.sprite/logs/services/web.log
```

A bad `--cmd` path looks like this:

```text theme={null}
2026-06-02T17:07:38.805Z [stderr] executable file `/usr/bin/does-not-exist` not found: No such file or directory
```

**The service keeps restarting.**

The runtime restarts crashing services, so a crash loop shows up as a climbing `restart_count` in `sprite-env services get <name>`. Read the log file to find out why it's crashing, and test the command by hand in a shell with the same `--dir` and `--env`.

**Requests to the Sprite's URL aren't reaching the service.**

Check that the service actually has the HTTP port: `sprite-env services list` and look for `http_port`. Without it, the proxy routes to port 8080, not to your service.

## Managing services from outside the Sprite

Everything on this page uses the in-Sprite CLI. The same operations are available from outside through the Sprites REST API at `/v1/sprites/{name}/services` and the SDKs, which is how you'd configure services as part of provisioning a fleet of Sprites. See the [Services API reference](https://sprites.dev/api/sprites/services) for endpoints and request schemas.

## Related documentation

<CardGroup cols={2}>
  <Card title="Keeping a Sprite Running" icon="layer" href="/sprites/keeping-sprites-running">
    Use the Tasks API to hold a Sprite open while work finishes
  </Card>

  <Card title="Working with Sprites" icon="terminal" href="/sprites/working-with-sprites">
    Lifecycle, networking, and URL authentication
  </Card>

  <Card title="CLI Commands" icon="terminal" href="/sprites/cli/commands">
    The full sprite CLI reference
  </Card>
</CardGroup>
