---
title: "Configuration"
description: "Local drop-in replacement services for CI and no-network sandboxes. Fully stateful, production-fidelity API emulation."
canonical_url: "https://emulate.dev/docs/configuration"
---
# Configuration

Configuration is optional. All services start with sensible defaults. To customize seed data, create `emulate.config.yaml` in your project root (or pass `--seed`):

```yaml
tokens:
  gho_test_token_admin:
    login: admin
    scopes:
      - repo
      - user
      - admin:org
      - admin:repo_hook
  gho_test_token_user1:
    login: octocat
    scopes:
      - repo
      - user
```

## Vercel Seed Config

```yaml
vercel:
  users:
    - username: developer
      name: Developer
      email: dev@example.com
  teams:
    - slug: my-team
      name: My Team
  projects:
    - name: my-app
      team: my-team
      framework: nextjs
      envVars:
        - key: DATABASE_URL
          value: postgres://localhost
          target: [production, preview]
```

## Vercel Integrations

Register Vercel OAuth integrations for strict client validation:

```yaml
vercel:
  integrations:
    - client_id: "oac_abc123"
      client_secret: "secret_abc123"
      name: "My Vercel App"
      redirect_uris:
        - "http://localhost:3000/api/auth/callback/vercel"
```

## GitHub Seed Config

```yaml
github:
  users:
    - login: octocat
      name: The Octocat
      email: octocat@github.com
      bio: I am the Octocat
      company: GitHub
      location: San Francisco

  orgs:
    - login: my-org
      name: My Organization
      description: A test organization
      members:
        - login: octocat
          role: admin

  repos:
    - owner: octocat
      name: hello-world
      description: My first repository
      language: JavaScript
      topics: [hello, world]
      auto_init: true
    - owner: my-org
      name: org-repo
      description: An organization repository
      language: TypeScript
      auto_init: true
```

GitHub organization `members` are optional. Each entry references a seeded user by `login`; `role` defaults to `member`, while `admin` creates an organization administrator. Unknown users are ignored.

## GitHub OAuth Apps

Register OAuth applications so the emulator validates `client_id`, `client_secret`, and `redirect_uri` during the OAuth flow:

```yaml
github:
  oauth_apps:
    - client_id: "Iv1.abc123"
      client_secret: "secret_abc123"
      name: "My Web App"
      redirect_uris:
        - "http://localhost:3000/api/auth/callback/github"
```

If no `oauth_apps` are configured, the emulator accepts any `client_id` (backward-compatible). With apps configured, strict validation is enforced.

## GitHub Apps

Full GitHub App support with JWT authentication and installation access tokens:

```yaml
github:
  apps:
    - app_id: 12345
      slug: "my-github-app"
      name: "My GitHub App"
      permissions:
        contents: read
        issues: write
      events: [push, pull_request]
      installations:
        - installation_id: 100
          account: my-org
          repository_selection: all
          permissions:
            contents: read
```

**Endpoints:**
- `GET /app` - get authenticated app (JWT required)
- `GET /app/installations` - list app installations
- `GET /app/installations/:id` - get installation
- `POST /app/installations/:id/access_tokens` - create installation access token
- `GET /_emulate/installation-tokens` - inspect secret-free metadata for minted installation tokens
- `GET /repos/:owner/:repo/installation` - find repo installation
- `GET /orgs/:org/installation` - find org installation
- `GET /users/:username/installation` - find user installation

JWT authentication: sign a JWT with `{ iss: "<app_id>" }` using the app's private key (RS256). The emulator verifies the signature and resolves the app.

When using the programmatic `createEmulator` API, omit `private_key`. The instance generates an RSA-2048 PKCS#1 key, exposes it through `generatedSecrets`, and keeps it stable across `reset()` calls. The CLI only generates an omitted key when you request a private delivery file:

```bash
npx emulate start --service github --seed emulate.config.yaml \
  --generated-secrets-file .emulate-secrets.json
```

The destination must not exist. emulate removes inherited ACLs, verifies effective owner-only access, and publishes complete JSON before opening listeners or configuring portless. Handled startup failures remove the invocation-owned artifact. A hard termination can leave a complete artifact that must be removed manually after confirming no invocation is using it. Explicit keys are excluded. Linux requires `setfacl` and `getfacl` from the `acl` package. The flag fails closed when access controls cannot be verified and is not supported on Windows. Without `--generated-secrets-file`, CLI seed files still require an explicit, valid private key. Do not replace an omitted key with a fake PEM placeholder.

## Google Seed Config

```yaml
google:
  users:
    - email: testuser@example.com
      name: Test User
    - email: admin@acme.com
      name: Admin
      hd: acme.com
  oauth_clients:
    - client_id: my-client-id.apps.googleusercontent.com
      client_secret: GOCSPX-secret
      redirect_uris:
        - http://localhost:3000/api/auth/callback/google
  labels:
    - id: Label_ops
      user_email: testuser@example.com
      name: Ops/Review
  messages:
    - id: msg_welcome
      user_email: testuser@example.com
      from: welcome@example.com
      to: testuser@example.com
      subject: Welcome to the Gmail emulator
      body_text: You can now test Gmail, Calendar, and Drive flows locally.
      label_ids: [INBOX, UNREAD]
  calendars:
    - id: primary
      user_email: testuser@example.com
      summary: testuser@example.com
      primary: true
  calendar_events:
    - id: evt_kickoff
      user_email: testuser@example.com
      calendar_id: primary
      summary: Project Kickoff
      start_date_time: 2025-01-10T09:00:00.000Z
      end_date_time: 2025-01-10T09:30:00.000Z
  drive_items:
    - id: drv_docs
      user_email: testuser@example.com
      name: Docs
      mime_type: application/vnd.google-apps.folder
      parent_ids: [root]
```

### Hosted domain (hd) claim

Google Workspace accounts include an `hd` claim in ID tokens and userinfo responses identifying the user's hosted domain. The emulator derives this automatically from the user's email domain. Consumer domains (`gmail.com`, `googlemail.com`) omit the claim, matching real Google behavior.

To override the derived value, set `hd` on a seeded user. To suppress the claim entirely, set `hd` to an empty string.

## Slack Seed Config

```yaml
slack:
  team:
    name: My Workspace
    domain: my-workspace
  users:
    - name: developer
      real_name: Developer
      email: dev@example.com
      is_admin: true
  channels:
    - name: general
      topic: General discussion
    - name: engineering
      topic: Engineering discussions
      is_private: true
  bots:
    - name: my-bot
  oauth_apps:
    - client_id: "12345.67890"
      client_secret: example_client_secret
      name: My Slack App
      redirect_uris:
        - http://localhost:3000/api/auth/callback/slack
      scopes:
        - chat:write
        - channels:read
        - users.profile:read
        - users.profile:write
        - users:write
        - files:read
        - files:write
        - pins:read
        - pins:write
        - bookmarks:read
        - bookmarks:write
  tokens:
    - token: xoxb-local-test
      user: developer
      scopes:
        - chat:write
        - channels:read
        - users.profile:read
        - users.profile:write
        - users:write
        - files:read
        - files:write
        - pins:read
        - pins:write
        - bookmarks:read
        - bookmarks:write
  incoming_webhooks:
    - channel: general
      label: CI Notifications
  signing_secret: my_signing_secret
```

`signing_secret` signs every outbound Slack event subscription callback, including existing subscriptions. Signed callbacks include `X-Slack-Request-Timestamp` and `X-Slack-Signature`, calculated as `v0=<HMAC-SHA256(secret, "v0:<timestamp>:<raw-body>")>` over the exact serialized body. Configure the receiver with the same secret and verify the unparsed request body. When the secret is absent or empty, callbacks are unsigned.

When no OAuth apps are configured, the emulator accepts any `client_id`. With apps configured, strict validation is enforced.

## Apple Seed Config

```yaml
apple:
  users:
    - email: testuser@icloud.com
      name: Test User
      given_name: Test
      family_name: User
    - email: private@example.com
      name: Private User
      is_private_email: true
  oauth_clients:
    - client_id: com.example.app
      team_id: TEAM001
      name: My Apple App
      redirect_uris:
        - http://localhost:3000/api/auth/callback/apple
```

Users with `is_private_email: true` get a generated `@privaterelay.appleid.com` email in the `id_token`.

## Microsoft Seed Config

```yaml
microsoft:
  users:
    - email: testuser@outlook.com
      name: Test User
      given_name: Test
      family_name: User
      tenant_id: 9188040d-6c67-4c5b-b112-36a304b66dad
  oauth_clients:
    - client_id: example-client-id
      client_secret: example-client-secret
      name: My Microsoft App
      redirect_uris:
        - http://localhost:3000/api/auth/callback/microsoft-entra-id
      tenant_id: 9188040d-6c67-4c5b-b112-36a304b66dad
```

## AWS Seed Config

```yaml
aws:
  region: us-east-1
  s3:
    buckets:
      - name: my-app-bucket
      - name: my-app-uploads
        region: eu-west-1
  sqs:
    queues:
      - name: my-app-events
      - name: my-app-dlq
        visibility_timeout: 60
      - name: my-app-orders.fifo
        fifo: true
  iam:
    users:
      - user_name: developer
        create_access_key: true
    roles:
      - role_name: lambda-execution-role
        description: Role for Lambda function execution
```

Default seed (always created): S3 bucket `emulate-default`, SQS queue `emulate-default-queue`, IAM user `admin` with access key pair.

## Okta Seed Config

```yaml
okta:
  users:
    - login: testuser@example.com
      email: testuser@example.com
      firstName: Test
      lastName: User
  groups:
    - name: Everyone
      description: All users
  apps:
    - name: My App
      label: My App
  authorization_servers:
    - name: default
      audiences: ["api://default"]
```

## MongoDB Atlas Seed Config

```yaml
mongoatlas:
  projects:
    - name: my-project
  clusters:
    - project: my-project
      name: my-cluster
  database_users:
    - project: my-project
      username: app-user
```

## Resend Seed Config

```yaml
resend:
  domains:
    - name: example.com
  api_keys:
    - name: default
```

## Stripe Seed Config

```yaml
stripe:
  customers:
    - email: test@example.com
      name: Test Customer
  products:
    - name: Pro Plan
      description: Monthly pro subscription
  prices:
    - product_name: Pro Plan
      currency: usd
      unit_amount: 2000
```

## Clerk Seed Config

```yaml
clerk:
  users:
    - first_name: Test
      last_name: User
      email_addresses:
        - test@example.com
      password: clerk_test_password
  organizations:
    - name: My Company
      slug: my-company
      members:
        - email: test@example.com
          role: admin
  oauth_applications:
    - client_id: clerk_emulate_client
      client_secret: clerk_emulate_secret
      name: Emulate App
      redirect_uris:
        - http://localhost:3000/api/auth/callback/clerk
```

## Linear Seed Config

```yaml
linear:
  organization:
    name: Acme
    url_key: acme
  users:
    - email: admin@example.com
      name: Admin User
      admin: true
    - email: dev@example.com
      name: Developer
  teams:
    - key: ENG
      name: Engineering
      states:
        - name: Backlog
          type: backlog
        - name: Todo
          type: unstarted
        - name: In Progress
          type: started
        - name: Done
          type: completed
  labels:
    - name: Bug
      color: "#d92d20"
      team: ENG
    - name: Feature
      color: "#2563eb"
      team: ENG
  issues:
    - team: ENG
      title: Fix local checkout test
      description: Reproduce and fix the checkout failure.
      state: Todo
      assignee: dev@example.com
      labels: [Bug]
  oauth_apps:
    - client_id: lin_example_client_id
      client_secret: example_client_secret
      name: My Linear App
      redirect_uris:
        - http://localhost:3000/api/auth/callback/linear
      scopes: [read, write, issues:create, comments:create]
      actor: user
  tokens:
    - token: lin_test_admin
      user: admin@example.com
      scopes: [read, write, issues:create, comments:create, admin]
  strict_scopes: false
```

## Twilio Seed Config

```yaml
twilio:
  account:
    sid: AC00000000000000000000000000000000
    auth_token: twilio_test_auth_token
    friendly_name: Local Twilio Account
  api_keys:
    - sid: SK00000000000000000000000000000000
      secret: twilio_test_api_secret
      friendly_name: Local API Key
  phone_numbers:
    - phone_number: "+15551234567"
      friendly_name: Local SMS and Voice Number
      sms_url: http://localhost:3000/api/twilio/sms
      voice_url: http://localhost:3000/api/twilio/voice
  messaging_services:
    - friendly_name: Local Messaging Service
      phone_numbers: ["+15551234567"]
  verify_services:
    - friendly_name: Local Verify Service
      code: "123456"
      default_channel: sms
  conversations:
    services:
      - friendly_name: Local Conversations
```

## Custom emulators

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