Custom Services
The Service entity wraps any command-line process. It works with any language or framework — if you can run it in a terminal, you can run it in Sigil.
Basic usage
Section titled “Basic usage”import { Service } from "sigil";
env.add( new Service("my-api", { command: ["node", "server.js"], cwd: "./backend", }));With environment variables
Section titled “With environment variables”Pass environment variables that get merged with the parent process environment:
env.add( new Service("my-api", { command: ["python", "-m", "uvicorn", "main:app", "--port", "8000"], cwd: "./backend", env: { DATABASE_URL: db.connectionString, REDIS_URL: "redis://localhost:6379", NODE_ENV: "development", }, }));With a ready check
Section titled “With a ready check”Without a ready check, Sigil marks the service as “running” as soon as the process spawns. With a ready check, it polls an HTTP endpoint until it responds:
env.add( new Service("my-api", { command: ["node", "server.js"], readyCheck: { url: "http://localhost:3000/health", interval: 1000, // poll every 1s (default) timeout: 30000, // fail after 30s (default) }, }));This is important when other services depend on this one being fully ready before they start.
Attaching interfaces
Section titled “Attaching interfaces”Interfaces are metadata describing what the service exposes:
import { Service, APIInterface, BrowserInterface } from "sigil";
// An API serviceenv.add( new Service("backend", config, [new APIInterface(8000)]));
// A web frontendenv.add( new Service("frontend", config, [new BrowserInterface(3000)]));Common patterns
Section titled “Common patterns”Python with virtualenv
Section titled “Python with virtualenv”import path from "path";const root = import.meta.dir;
env.add( new Service("api", { command: [ path.join(root, "backend/.venv/bin/uvicorn"), "main:app", "--host", "0.0.0.0", "--port", "8000", ], cwd: path.join(root, "backend"), }));Go binary
Section titled “Go binary”env.add( new Service("api", { command: ["go", "run", "."], cwd: "./backend", env: { PORT: "8080" }, readyCheck: { url: "http://localhost:8080/healthz" }, }));Bun/Node dev server
Section titled “Bun/Node dev server”env.add( new Service("frontend", { command: ["bun", "run", "dev"], cwd: "./frontend", readyCheck: { url: "http://localhost:5173" }, }));Stdout/stderr
Section titled “Stdout/stderr”Service output is streamed to the terminal with a name prefix:
[my-api] Server listening on port 8000[my-api] Connected to database[frontend] VITE v5.0.0 ready in 200msLifecycle
Section titled “Lifecycle”- Start: Process is spawned via
Bun.spawn(). If areadyCheckis configured, Sigil polls until the endpoint responds with a 2xx status. - Stop: Process receives
SIGKILL. The service status transitions to"stopped".