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

# Run services

> Create, start, stop, and read logs from supervised services in a Devbox.

Use `devbox.services` to run long-lived commands, such as development servers, that the Devbox agent supervises. The agent restarts a service according to its restart policy, retains its output, and by default starts it again when the Devbox boots. Use this page to create, inspect, start, stop, and delete services, and to read their logs.

<Info>
  Service operations start a stopped Devbox automatically. Service definitions persist with the Devbox and continue running after the client disconnects.
</Info>

See [Services](/docs/devbox/services) for an overview of services, including how to manage them from the Devbox CLI.

## `services.create()`

Use `services.create()` to define a supervised command and start it. The agent runs the executable directly, without a shell, so arguments are passed literally. Run `sh -c` as the command when the service needs pipelines, redirects, or command chaining.

<h3 id="services-create-example">
  Example
</h3>

Create a service that runs a development server from the workspace:

```typescript {2-7} theme={null}
const devbox = await client.devboxes.get("sdk-example");
const service = await devbox.services.create({
  name: "web",
  command: "npm",
  args: ["run", "dev"],
  cwd: "app",
});
console.log(service.id, service.process?.state);
```

<h3 id="services-create-api-reference">
  API reference
</h3>

```typescript theme={null}
services.create(input: CreateServiceInput, options?: OperationOptions): Promise<Service>
```

<h4 id="services-create-arguments-and-options">
  Arguments and options
</h4>

<ResponseField name="input" type="CreateServiceInput" required>
  The service definition.

  <Expandable title="properties" defaultOpen>
    <ResponseField name="name" type="string" required>
      The service name. It must not be empty or contain only whitespace.
    </ResponseField>

    <ResponseField name="command" type="string" required>
      The executable name or path. It must not be empty. The command is not evaluated by a shell.
    </ResponseField>

    <ResponseField name="args" type="readonly string[]">
      Arguments passed literally to the executable.
    </ResponseField>

    <ResponseField name="cwd" type="string">
      The working directory. Absolute paths are used as provided. Relative paths resolve from the Devbox workspace directory.
    </ResponseField>

    <ResponseField name="environment" type="Record<string, string | { secretId: string }>">
      Environment variable overrides. Each value is either a literal string or a `{ secretId }` object that references a Vault secret, which the Devbox agent resolves when the process starts. Names must start with a letter or underscore and contain only letters, numbers, and underscores. A secret reference must have a non-empty `secretId`.
    </ResponseField>

    <ResponseField name="description" type="string">
      A description of the service.
    </ResponseField>

    <ResponseField name="start" type="boolean">
      Whether to start the service now. Omit it to follow `startPolicy`. `true` starts the service immediately. `false` creates the service in a durably stopped state, so it does not start until you call [`services.start()`](#services-start).
    </ResponseField>

    <ResponseField name="startPolicy" type="&#x22;on-boot&#x22; | &#x22;manual&#x22;" default="on-boot">
      When the service starts automatically. `on-boot` starts the service on creation and whenever the Devbox agent boots. `manual` starts it only when requested.
    </ResponseField>

    <ResponseField name="restartPolicy" type="&#x22;never&#x22; | &#x22;on-failure&#x22; | &#x22;always&#x22;" default="on-failure">
      When the agent restarts the service after its process exits.
    </ResponseField>

    <ResponseField name="preventIdleShutdown" type="boolean" default="false">
      Whether the Devbox stays active instead of shutting down for inactivity while the service process is running.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="options" type="OperationOptions">
  Supports `signal` and `timeoutMs`. See [Handle errors and timeouts](/docs/reference/typescript-sdk/devbox/errors#operationoptions).
</ResponseField>

Invalid input rejects with a `TypeError` before any request is sent.

<h4 id="services-create-return-value">
  Return value
</h4>

`services.create()` resolves with the created [`Service`](#service). Its `process` field reflects the state the agent observed after its initial launch wait. It does not confirm that the process launched successfully or that the application is ready to accept requests. A launch failure is reported in `process.state` and `process.lastExit` rather than as a rejection.

<h3 id="services-create-more-examples">
  More examples
</h3>

#### Run a shell command with environment variables

```typescript {2-10} theme={null}
const devbox = await client.devboxes.get("sdk-example");
await devbox.services.create({
  name: "api",
  command: "sh",
  args: ["-c", "npm install && npm start"],
  environment: {
    PORT: "8080",
    API_TOKEN: { secretId: "secret-id" },
  },
  restartPolicy: "always",
});
```

#### Create a service without starting it

```typescript {2-7} theme={null}
const devbox = await client.devboxes.get("sdk-example");
await devbox.services.create({
  name: "worker",
  command: "node",
  args: ["worker.js"],
  startPolicy: "manual",
});
```

***

## `services.get()`

Use `services.get()` to look up a single service by ID or name.

<h3 id="services-get-example">
  Example
</h3>

```typescript {2-3} theme={null}
const devbox = await client.devboxes.get("sdk-example");
const service = await devbox.services.get("web");
console.log(service.process?.state ?? "not started");
```

<h3 id="services-get-api-reference">
  API reference
</h3>

```typescript theme={null}
services.get(ref: string, options?: OperationOptions): Promise<Service>
```

<h4 id="services-get-arguments-and-options">
  Arguments and options
</h4>

<ResponseField name="ref" type="string" required>
  The exact service ID, or the name of a user-owned service. IDs are matched before names. The value must not be empty.
</ResponseField>

<ResponseField name="options" type="OperationOptions">
  Supports `signal` and `timeoutMs`. See [Handle errors and timeouts](/docs/reference/typescript-sdk/devbox/errors#operationoptions).
</ResponseField>

<h4 id="services-get-return-value">
  Return value
</h4>

`services.get()` resolves with the matching [`Service`](#service). It lists the Devbox's services and selects the match on the client. It rejects with `ServiceNotFoundError` when no service matches.

***

## `services.list()`

Use `services.list()` to list the services defined on the Devbox.

<h3 id="services-list-example">
  Example
</h3>

```typescript {2-5} theme={null}
const devbox = await client.devboxes.get("sdk-example");
const services = await devbox.services.list();
for (const service of services) {
  console.log(service.name, service.process?.state ?? "not started");
}
```

<h3 id="services-list-api-reference">
  API reference
</h3>

```typescript theme={null}
services.list(options?: OperationOptions): Promise<Service[]>
```

<h4 id="services-list-arguments-and-options">
  Arguments and options
</h4>

<ResponseField name="options" type="OperationOptions">
  Supports `signal` and `timeoutMs`. See [Handle errors and timeouts](/docs/reference/typescript-sdk/devbox/errors#operationoptions).
</ResponseField>

<h4 id="services-list-return-value">
  Return value
</h4>

`services.list()` resolves with a [`Service`](#service) for each service the Devbox agent reports, including services owned by Namespace. Check `owner` to distinguish them.

***

## `services.start()`

Use `services.start()` to start a service, including one that was stopped or created with `start: false`. It clears the service's durable stopped state and starts it regardless of its start policy.

<h3 id="services-start-example">
  Example
</h3>

```typescript {2-3} theme={null}
const devbox = await client.devboxes.get("sdk-example");
const serviceProcess = await devbox.services.start("web");
console.log(serviceProcess.state, serviceProcess.pid);
```

<h3 id="services-start-api-reference">
  API reference
</h3>

```typescript theme={null}
services.start(ref: string, options?: OperationOptions): Promise<ServiceProcess>
```

<h4 id="services-start-arguments-and-options">
  Arguments and options
</h4>

<ResponseField name="ref" type="string" required>
  The service ID or name. The value must not be empty.
</ResponseField>

<ResponseField name="options" type="OperationOptions">
  Supports `signal` and `timeoutMs`. See [Handle errors and timeouts](/docs/reference/typescript-sdk/devbox/errors#operationoptions).
</ResponseField>

<h4 id="services-start-return-value">
  Return value
</h4>

`services.start()` resolves with the [`ServiceProcess`](#serviceprocess) the agent observed after its initial launch wait. As with `services.create()`, this does not confirm that the process launched or that the application is ready. It rejects with `ServiceNotFoundError` when the agent has no matching service.

***

## `services.stop()`

Use `services.stop()` to stop a service and keep it stopped. The service is durably marked as stopped, so it does not start again automatically, including when the Devbox boots, until you call [`services.start()`](#services-start). The promise resolves once termination is requested, without waiting for the process to exit.

<h3 id="services-stop-example">
  Example
</h3>

```typescript {2} theme={null}
const devbox = await client.devboxes.get("sdk-example");
await devbox.services.stop("web");
```

<h3 id="services-stop-api-reference">
  API reference
</h3>

```typescript theme={null}
services.stop(ref: string, options?: StopServiceOptions): Promise<ServiceProcess | undefined>
```

<h4 id="services-stop-arguments-and-options">
  Arguments and options
</h4>

<ResponseField name="ref" type="string" required>
  The service ID or name. The value must not be empty.
</ResponseField>

<ResponseField name="options" type="StopServiceOptions">
  Options for stopping the service.

  <Expandable title="properties" defaultOpen>
    <ResponseField name="mode" type="&#x22;graceful&#x22; | &#x22;force&#x22;" default="graceful">
      `graceful` terminates the process in a way that allows it to clean up. `force` kills it immediately. Any other value rejects with a `TypeError`.
    </ResponseField>

    <ResponseField name="signal" type="AbortSignal">
      Cancels the request when the signal is aborted.
    </ResponseField>

    <ResponseField name="timeoutMs" type="number">
      The timeout in milliseconds for activating the Devbox, connecting, and sending the stop request.
    </ResponseField>
  </Expandable>
</ResponseField>

<h4 id="services-stop-return-value">
  Return value
</h4>

`services.stop()` resolves with the [`ServiceProcess`](#serviceprocess) reported by the agent, or `undefined` when the response includes no process. The process may still be in the `stopping` state. Call [`services.get()`](#services-get) to observe when it exits. The method rejects with `ServiceNotFoundError` when the agent has no matching service.

***

## `services.delete()`

Use `services.delete()` to permanently remove a service. The agent stops the service gracefully and escalates to forced termination after 15 seconds.

<h3 id="services-delete-example">
  Example
</h3>

```typescript {2} theme={null}
const devbox = await client.devboxes.get("sdk-example");
await devbox.services.delete("web");
```

<h3 id="services-delete-api-reference">
  API reference
</h3>

```typescript theme={null}
services.delete(ref: string, options?: OperationOptions): Promise<void>
```

<h4 id="services-delete-arguments-and-options">
  Arguments and options
</h4>

<ResponseField name="ref" type="string" required>
  The service ID or name. The value must not be empty.
</ResponseField>

<ResponseField name="options" type="OperationOptions">
  Supports `signal` and `timeoutMs`. See [Handle errors and timeouts](/docs/reference/typescript-sdk/devbox/errors#operationoptions).
</ResponseField>

<h4 id="services-delete-return-value">
  Return value
</h4>

`services.delete()` resolves when the service is removed. It rejects with `ServiceNotFoundError` when the agent has no matching service. If the agent cannot complete the deletion within 20 seconds, it rejects with a `ConnectError` whose code is `DeadlineExceeded`, even when your own `timeoutMs` has not elapsed.

***

## `services.logs()`

Use `services.logs()` to stream a service's output. The iterator first replays the output retained for the service's latest run, then follows that run's live output. It does not switch to runs that start later. Automatic restart attempts may share the same run.

<h3 id="services-logs-example">
  Example
</h3>

```typescript {2-5} theme={null}
const devbox = await client.devboxes.get("sdk-example");
for await (const chunk of devbox.services.logs("web")) {
  process.stdout.write(chunk.stdout);
  process.stderr.write(chunk.stderr);
}
```

<h3 id="services-logs-api-reference">
  API reference
</h3>

```typescript theme={null}
services.logs(ref: string, options?: OperationOptions): AsyncIterableIterator<ExecutionLogChunk>
```

<h4 id="services-logs-arguments-and-options">
  Arguments and options
</h4>

<ResponseField name="ref" type="string" required>
  The exact service ID, or the name of a user-owned service. The value must not be empty.
</ResponseField>

<ResponseField name="options" type="OperationOptions">
  Supports `signal` and `timeoutMs`. Connecting to the Devbox is bounded by the client's `connectionTimeoutMs` instead, and `timeoutMs` starts once the connection is established.
</ResponseField>

<h4 id="services-logs-return-value">
  Return value
</h4>

`services.logs()` returns an async iterator of the same [`ExecutionLogChunk`](/docs/reference/typescript-sdk/devbox/commands#execution-logs-return-value) objects as `execution.logs()`. A chunk with a `result` is delivered when the run ends.

The iterator throws `ServiceNotFoundError` when no service matches `ref`, and `ServiceLogsNotFoundError` when the service has no retained run whose output can be read, for example because it has never started.

Each call opens an independent reader. Breaking out of the loop or aborting `signal` closes only that reader and does not stop the service.

## Service types

### `Service`

`services.create()`, `services.get()`, and `services.list()` return a `Service` snapshot of the service's state as observed from the Devbox agent. It does not update after it is returned.

```typescript theme={null}
interface Service {
  id: string;
  name: string;
  command: string;
  args: string[];
  cwd?: string;
  environment: Record<string, string | { secretId: string }>;
  description?: string;
  startPolicy: "on-boot" | "manual" | "on-http-ingress" | "unknown";
  restartPolicy: "never" | "on-failure" | "always" | "unknown";
  preventIdleShutdown: boolean;
  stopped: boolean;
  owner: "user" | "namespace" | "unknown";
  ports: ServicePort[];
  process?: ServiceProcess;
}
```

<ResponseField name="id" type="string" required>
  The service ID assigned by the Devbox agent.
</ResponseField>

<ResponseField name="name" type="string" required>
  The service name.
</ResponseField>

<ResponseField name="command" type="string" required>
  The executable name or path.
</ResponseField>

<ResponseField name="args" type="string[]" required>
  The arguments passed to the executable. Empty when the service has no arguments.
</ResponseField>

<ResponseField name="cwd" type="string">
  The configured working directory, either absolute or relative to the Devbox workspace directory.
</ResponseField>

<ResponseField name="environment" type="Record<string, string | { secretId: string }>" required>
  The configured environment overrides. This is not the complete environment of the running process.
</ResponseField>

<ResponseField name="description" type="string">
  The service description, when one is set.
</ResponseField>

<ResponseField name="startPolicy" type="&#x22;on-boot&#x22; | &#x22;manual&#x22; | &#x22;on-http-ingress&#x22; | &#x22;unknown&#x22;" required>
  When the service starts automatically. `on-http-ingress` can be reported for services created outside the TypeScript SDK, but `services.create()` does not accept it.
</ResponseField>

<ResponseField name="restartPolicy" type="&#x22;never&#x22; | &#x22;on-failure&#x22; | &#x22;always&#x22; | &#x22;unknown&#x22;" required>
  When the agent restarts the service after its process exits.
</ResponseField>

<ResponseField name="preventIdleShutdown" type="boolean" required>
  Whether the service keeps the Devbox active while its process is running.
</ResponseField>

<ResponseField name="stopped" type="boolean" required>
  Whether automatic starts are durably suppressed by [`services.stop()`](#services-stop) or `start: false`. It does not confirm that the process has exited. Check `process.state` for that.
</ResponseField>

<ResponseField name="owner" type="&#x22;user&#x22; | &#x22;namespace&#x22; | &#x22;unknown&#x22;" required>
  Who manages the service. `namespace` identifies services managed by Namespace rather than created by a user.
</ResponseField>

<ResponseField name="ports" type="ServicePort[]" required>
  The ports attached to the service. See [`ServicePort`](#serviceport).
</ResponseField>

<ResponseField name="process" type="ServiceProcess">
  The state of the service's process. See [`ServiceProcess`](#serviceprocess). Absent when the agent reports no process.
</ResponseField>

### `ServiceProcess`

`services.start()` and `services.stop()` return a `ServiceProcess`, and `Service.process` uses the same type.

```typescript theme={null}
interface ServiceProcess {
  state: "starting" | "running" | "stopping" | "stopped" | "failed" | "restarting" | "unknown";
  pid?: number;
  startedAt?: Date;
  restartCount: number;
  lastExit?: {
    exitCode: number;
    error?: string;
    exitedAt?: Date;
  };
}
```

<ResponseField name="state" type="&#x22;starting&#x22; | &#x22;running&#x22; | &#x22;stopping&#x22; | &#x22;stopped&#x22; | &#x22;failed&#x22; | &#x22;restarting&#x22; | &#x22;unknown&#x22;" required>
  The process state. `restarting` means the process exited and the agent is waiting to start it again. `failed` means the agent is no longer restarting it.
</ResponseField>

<ResponseField name="pid" type="number">
  The process ID, when a process is running.
</ResponseField>

<ResponseField name="startedAt" type="Date">
  When the current process started, when the agent reports it.
</ResponseField>

<ResponseField name="restartCount" type="number" required>
  The number of automatic restarts since the service was last explicitly started. It is not a lifetime total.
</ResponseField>

<ResponseField name="lastExit" type="{ exitCode: number; error?: string; exitedAt?: Date }">
  How the most recent process exited, including agent-reported failure detail in `error`. While the service is still active, it may describe an earlier attempt.
</ResponseField>

### `ServicePort`

Ports are read-only in the TypeScript SDK. `services.create()` cannot attach ports to a service. To publish a service's HTTP port, use [`devbox.exposedPorts`](/docs/reference/typescript-sdk/devbox/exposed-ports).

```typescript theme={null}
interface ServicePort {
  id: string;
  name?: string;
  number: number;
  kind: "port-forward" | "http-ingress" | "unknown";
  owner: "user" | "namespace" | "unknown";
}
```

<ResponseField name="id" type="string" required>
  The port ID.
</ResponseField>

<ResponseField name="name" type="string">
  The port name, when one is set.
</ResponseField>

<ResponseField name="number" type="number" required>
  The port number.
</ResponseField>

<ResponseField name="kind" type="&#x22;port-forward&#x22; | &#x22;http-ingress&#x22; | &#x22;unknown&#x22;" required>
  How the port is made reachable.
</ResponseField>

<ResponseField name="owner" type="&#x22;user&#x22; | &#x22;namespace&#x22; | &#x22;unknown&#x22;" required>
  Who manages the port.
</ResponseField>

## Related documentation

<Columns cols={3}>
  <Card title="Services" icon="server" href="/docs/devbox/services">
    Learn how Devbox services work.
  </Card>

  <Card title="Run commands" icon="terminal" href="/docs/reference/typescript-sdk/devbox/commands">
    Run one-off and background commands.
  </Card>

  <Card title="Handle errors and timeouts" icon="triangle-alert" href="/docs/reference/typescript-sdk/devbox/errors">
    Cancel operations and handle SDK failures.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.