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

# Configuration

> The config file, tokens, shared identities, ports, faults, and the control API: settings every provider shares.

Configuration is optional. All services start with sensible defaults. To customize seed data, create `baseline.config.json` in your project root (or pass `--seed`). Run `npx @deploybaseline/cli init` to generate a starter file:

```json baseline.config.json theme={null}
{
  "$schema": "https://unpkg.com/@deploybaseline/cli@0.14.0/baseline.config.schema.json",
  "tokens": {
    "gho_test_token_admin": {
      "login": "admin",
      "scopes": ["repo", "user", "admin:org", "admin:repo_hook"]
    },
    "gho_test_token_user1": {
      "login": "octocat",
      "scopes": ["repo", "user"]
    }
  }
}
```

The `$schema` line points editors such as VS Code and JetBrains IDEs at the config schema, so they complete keys and flag mistakes while you type. `init` and `convert` write the URL for the CLI's own version, so the editor checks what that CLI accepts; change the version in the URL when you upgrade. It is optional, and the CLI ignores it.

The CLI also reads `baseline.config.ts` / `.mts` / `.js` / `.mjs` (see [Custom emulators](https://docs.deploybaseline.com/custom-emulators.md)), `baseline.config.yaml` / `.yml`, and the older `service-emulator.config.json` / `.yaml` / `.yml`. Keep one config file per folder: with more than one, `start` asks you to choose with `--config`.

## Checking a config

`validate` checks a config file without starting anything and names each problem with its line and column, the setting, and a fix:

```bash theme={null}
npx @deploybaseline/cli validate
```

```text theme={null}
invalid baseline.config.json: 2 problems

baseline.config.json:4:37
  github.users[0].nmae: unknown property "nmae"
  fix: Did you mean "name"?
    3 |   "github": {
    4 |     "users": [{ "login": "octocat", "nmae": "Octo" }],
      |                                     ^
    5 |     "repos": [{ "owner": "octocat", "name": "hello", "private": "true" }]

baseline.config.json:5:65
  github.repos[0].private: must be true or false, not the string "true"
  fix: Remove the quotes: true
    4 |     "users": [{ "login": "octocat", "nmae": "Octo" }],
    5 |     "repos": [{ "owner": "octocat", "name": "hello", "private": "true" }]
      |                                                                 ^
    6 |   }

Run validate again after fixing these: the checks `start` runs come next.
```

It runs three checks, each once the one before it passes:

1. **Syntax.** A `.json` file must be strict JSON. Trailing commas, comments, single quotes, and unquoted names are reported where they are, with the fix. Duplicate keys are reported too, since JSON would silently keep the last one.
2. **Shape.** Every key and value is checked against `baseline.config.schema.json`, which holds each provider's seed shape: unknown keys (with the closest known one), missing required fields, wrong types, and values outside a fixed set. A service under `services` with `emulator: stripe` has its `seed` checked as Stripe seed data.
3. **Meaning.** The checks `start` runs when it loads the config: custom emulator modules, version ranges, ports, and shared identities.

`validate <file>` checks another file, and `--json` prints the result as JSON (`valid`, and `problems` with `path`, `line`, `column`, `message`, and `hint`) for scripts and agents. It exits `1` when there are problems, so CI can run it before the tests. `start` runs the same shape check and prints a warning for each problem, then starts anyway. Seeds for provider packages that are not built in (`provider: npm:...`) and custom emulators are checked by that code when it starts.

To move a YAML config to JSON, run `convert`. It writes `baseline.config.json` beside the YAML file with `$schema` added, checks it, and leaves the YAML file for you to delete. JSON has no comments, so it tells you how many were left behind:

```bash theme={null}
npx @deploybaseline/cli convert baseline.config.yaml
```

## Shared identities

`identities` declares people once and seeds each of them as a user in every selected provider that has users (GitHub, Google, Slack, Apple, Microsoft, Okta, Clerk, Linear, Jira, Auth0, and Salesforce). One person then signs in to GitHub, Google, Slack, and Okta with the same email:

```json theme={null}
{
  "identities": [
    {
      "name": "Ada Lovelace",
      "email": "ada@example.com",
      "username": "ada",
      "avatar": "https://example.com/ada.png",
      "providers": {
        "github": {
          "login": "countess",
          "site_admin": true
        },
        "slack": false
      }
    }
  ],
  "github": {},
  "google": {},
  "slack": {},
  "okta": {}
}
```

* `username`: login where a provider has one; defaults to the part before "@"
* `github`: fields merged over the mapped user
* `slack`: leave Ada out of Slack

Each identity is mapped to the provider's own user fields (for example `login` on GitHub, `first_name` and `last_name` on Okta, `email_addresses` on Clerk). The first word of `name` becomes the given name and the rest the family name. Users listed in a provider's own section come first, so the default token user does not change, and an identity whose email that section already lists is skipped. Identities apply to the CLI and config files; with `createEmulator`, pass users in the service's seed.

## Saved state

`state` keeps every service's data, tokens, and webhook subscriptions across restarts. It is the config form of `--state`:

```json theme={null}
{
  "state": ".baseline/state.json"
}
```

or, with a save delay:

```json theme={null}
{
  "state": {
    "url": ".baseline/state.json",
    "saveDebounceMs": 250
  }
}
```

A relative path resolves against the config file's folder. `url` also takes `sqlite:.baseline/state.db` or a `libsql://` URL; keep a libSQL token out of the config file with `BASELINE_STATE_AUTH_TOKEN`. Saved state wins over seed config; see [Saved state](https://docs.deploybaseline.com/state.md) for precedence, `--reset-state`, watch reloads, locking, and [SQLite and Turso](https://docs.deploybaseline.com/state.md#sqlite-and-turso).

## Ports

With no config and no `--service`, each service listens on the base port plus its fixed slot (GitHub 4001 through Twilio 4012, see [Getting started](https://docs.deploybaseline.com/index.md)). Slots never change between releases: new providers are added after Twilio, and they start only when you name them in config or `--service`.

When config or `--service` names services, they take consecutive ports from the base port, in that same order. To keep a port stable no matter which services you run, set `port` per service:

```json theme={null}
{
  "github": {
    "port": 4001
  },
  "stripe": {
    "port": 4009
  }
}
```

### Console port

The console listens one below the base port (`3999` by default). It serves the [API reference](https://docs.deploybaseline.com/api-reference.md) for the services you started at `/docs`, and the control API below. `--console-port <port>` moves it and `--no-console` turns it off. A service set to the console port is an error at start, and when another program holds the port, the services start without the console.

### One process per service

Each built-in service runs in its own process and listens on its own port. Its output is prefixed with `[<service>]`. A service that crashes restarts on the same port from the last state Baseline saved for it, up to three times a minute; after that it stays down until you restart Baseline. Custom emulators from a config file run in the CLI's own process.

### Single port

`--single-port` is not supported. With every service in its own process, nothing sits in front of them to route `/<service>` paths, so the flag stops at start with an error. In a container, publish the port range instead and point each SDK at its service's port:

```bash theme={null}
docker run -p 3999-4031:3999-4031 ...
```

## Fault injection

Add latency and errors to any service to test retries and timeouts. Faults are off unless configured. Set them per service in config:

```json theme={null}
{
  "stripe": {
    "faults": {
      "seed": 42,
      "rules": [
        {
          "match": "POST /v1/payment_intents",
          "rate": 0.2,
          "response": {
            "status": 500
          }
        },
        {
          "match": "*",
          "latency_ms": 300
        }
      ]
    }
  }
}
```

* `seed`: same sequence of failures every run
* `rate`: 20% of matching requests

`match` is `"*"`, a path, or `"METHOD /path"`; paths may use `*` and `:param` segments. A rule needs `latency_ms`, `response` (`status`, optional `body` and `headers`), or both. Presets: `faults: { profile: degraded }` (300 ms latency and 10% 503s) and `faults: { profile: throttled }` (30% 429s with `Retry-After`). Injected responses carry `X-Baseline-Fault: injected`. `createEmulator({ service, faults })` (or `faults` in its seed) takes the same config.

## Control API

The [console port](#console-port) and every service port answer `/_baseline/control` and `/_baseline/faults` for the whole run. Start prints the console's address. Start prints a per-process token; send it as `X-Baseline-Control-Token`. Requests must use a loopback host or a configured base URL host, and cross-site requests are rejected. Start also prints an inspector link to `/_baseline/control/inspector` with the token in it, with a Faults tab and a State tab. Opening the link swaps the token for an `HttpOnly`, `SameSite=Strict` cookie that only allows reads, so API changes always need the header; the State tab's buttons carry a form token that only the inspector page holds. `/_baseline/state` serves the state endpoints (see [Saved state](https://docs.deploybaseline.com/state.md#named-snapshots)).

```bash theme={null}
curl -H "X-Baseline-Control-Token: $TOKEN" http://localhost:4009/_baseline/faults
curl -X POST -H "X-Baseline-Control-Token: $TOKEN" -H "Content-Type: application/json" \
  -d '{"service":"stripe","faults":{"profile":"throttled"}}' http://localhost:4009/_baseline/faults
curl -X DELETE -H "X-Baseline-Control-Token: $TOKEN" http://localhost:4009/_baseline/faults/stripe
```

Each CLI process writes its token and ports to `.baseline/run/<pid>.json` (owner-only) next to your config, so scripts can find them. Add `.baseline/` to `.gitignore`.

## Provider seed config

Each provider's seed keys, with a full example, are in the **Seed config** section of its page: for example [GitHub](https://docs.deploybaseline.com/github.md#seed-config), [Stripe](https://docs.deploybaseline.com/stripe.md#seed-config), or [Slack](https://docs.deploybaseline.com/slack.md#seed-config). [Providers](https://docs.deploybaseline.com/providers.md) lists every page. Every provider's section goes under its service name at the top level of the config file, next to the shared keys on this page.

Next to the seed keys, a provider's section takes `port`, `baseUrl`, `faults`, and `version`, the provider version range to run (such as `"^0.14"`). `start` pins the exact version in `baseline.lock`; see [Provider versions](https://docs.deploybaseline.com/provider-versions.md).

## OIDC signing keys

Google, Microsoft, Apple, Okta, Clerk, and Auth0 sign ID tokens (and Clerk session tokens and Auth0 access tokens) with an RS256 key kept in emulator state under `<service>.signing_keys`. The key is generated on first use and stays with that state, so tokens keep verifying after a snapshot restore or a restart from adapter persistence. A reset generates a new key unless one is pinned. Each provider keeps a fixed `kid`: `baseline-google-1`, `baseline-microsoft-1`, `baseline-apple-1`, `baseline-okta-1`, `baseline-clerk-1`, and `baseline-auth0-1`.

To pin the key, for example to verify tokens in your own tests with a known public key, set `signing_key.private_jwk` to an RSA private JWK. The option is the same under `google`, `microsoft`, `apple`, `okta`, `clerk`, and `auth0`:

```json theme={null}
{
  "google": {
    "signing_key": {
      "private_jwk": {
        "kty": "RSA",
        "n": "<modulus>",
        "e": "AQAB",
        "d": "<private exponent>",
        "p": "<prime 1>",
        "q": "<prime 2>",
        "dp": "<exponent 1>",
        "dq": "<exponent 2>",
        "qi": "<coefficient>"
      }
    }
  }
}
```

The JWKS endpoint serves only the public part. A `kid` on the JWK replaces the provider default. Generate a key with:

```bash theme={null}
node -e "console.log(JSON.stringify(require('crypto').generateKeyPairSync('rsa',{modulusLength:2048}).privateKey.export({format:'jwk'})))"
```

When persisted state is restored, the saved key is used and the seed is not applied again until the state is reset.

## Custom emulators

Custom definitions created with `defineEmulator` from `@deploybaseline/cli` work in the CLI and in in-process tests. The same definition provides typed state, HTTP handlers, reset, versioned snapshots, and optional inspection/persistence. See [Custom emulators](https://docs.deploybaseline.com/custom-emulators.md) for the quickstart, API reference, and complete lifecycle semantics.

## Provider packages

A service can run a provider package from npm that is not built in, in its own process like the built-in providers. Name it with `provider:` and give it a port:

```json theme={null}
{
  "services": {
    "billing": {
      "provider": "npm:@acme/baseline-billing@^1.2.0",
      "port": 4100
    }
  }
}
```

It runs only once you trust that version: `start` asks in a terminal and pins it in `baseline.lock`, and CI runs it once the committed lockfile trusts it (`npx @deploybaseline/cli trust billing`). See [Provider packages](https://docs.deploybaseline.com/provider-authors.md).

## Known limits

* A watch reload (`--watch`) restarts every provider, including those whose config did not change.
* `--single-port` is refused (see [Single port](#single-port)).
* The control token and host checks cover the `/_baseline/*` routes only. Service routes and WebSocket upgrades (Slack Socket Mode, the Discord Gateway) answer any host, so with `--host 0.0.0.0` they are reachable from the network.
* `createEmulator` runs built-in services and custom emulators. It does not take `provider:` packages, and it does not apply shared `identities:`.


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