Local drop-in API emulator for Vercel, GitHub, Google, Slack, Apple, Microsoft, AWS, Linear, and other developer APIs. Use when the user needs to start emulated services, configure seed data, write tests against local APIs, set up CI without network access, or work with the emulate CLI or programmatic API. Triggers include "start the emulator", "emulate services", "mock API locally", "create emulator config", "test against local API", "npx emulate", or any task requiring local service emulation.
Local drop-in API emulator for Vercel, GitHub, Google, Slack, Apple, Microsoft, AWS, Linear, and other developer APIs. Use when the user needs to start emulated services, configure seed data, write tests against local APIs, set up CI without network access, or work with the emulate CLI or programmatic API. Triggers include "start the emulator", "emulate services", "mock API locally", "create emulator config", "test against local API", "npx emulate", or any task requiring local service emulation.
allowed-tools
Bash(npx emulate:*)
Service Emulation with emulate
Local drop-in replacement services for CI and no-network sandboxes. Fully stateful, production-fidelity API emulation, not mocks.
Quick Start
npx emulate
All services start with sensible defaults:
Service
Default Port
Vercel
4000
GitHub
4001
Google
4002
Slack
4003
Apple
4004
Microsoft
4005
Okta
4006
AWS
4007
Resend
4008
Stripe
4009
MongoDB Atlas
4010
Clerk
4011
Linear
4012
Twilio
4013
CLI
# Start all services (zero-config)
npx emulate# Start specific services
npx emulate --service vercel,github
# Custom base port (auto-increments per service)
npx emulate --port 3000
# Use a seed config file
npx emulate --seed config.yaml
# Generate omitted service secrets into a private file
npx emulate start --seed config.yaml --generated-secrets-file .emulate-secrets.json
# Generate a starter config
npx emulate init
# Generate config for a specific service
npx emulate init --service vercel
# List available services
npx emulate list
Options
Flag
Default
Description
-p, --port
4000
Base port (auto-increments per service)
-s, --service
all
Comma-separated services to enable
--seed
auto-detect
Path to seed config (YAML or JSON)
--base-url
none
Override advertised base URL (supports {service} template)
--portless
off
Serve over HTTPS via portless (auto-registers aliases)
--generated-secrets-file
none
Generate omitted service secrets and write them to a new owner-only JSON file
The port can also be set via EMULATE_PORT or PORT environment variables.
The generated-secrets 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. Only service-generated values appear in the artifact. 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.
The advertised base URL (used in OAuth redirects, webhook URLs, etc.) can be overridden via --base-url, the EMULATE_BASE_URL env var (supports {service} template), or per-service baseUrl in the seed config. When running under portless, the PORTLESS_URL env var is also detected automatically.
Programmatic API
npm install emulate
Each call to createEmulator starts a single service:
Override advertised base URL. Per-service baseUrl in seed config takes highest priority, then this option, then EMULATE_BASE_URL env var (supports {service}), then PORTLESS_URL (supports {service}, automatically set by the portless CLI wrapper), then http://localhost:<port>.
Tokens map to users. Pass them as Authorization: Bearer <token> or Authorization: token <token>. When no tokens are configured, a default test_token_admin is created for the admin user.
Each service also has a fallback user. If no token is provided, requests authenticate as the first seeded user.
HTTPS with portless
portless gives emulators trusted HTTPS URLs with auto-generated certs. Use the --portless flag to auto-register each service as a portless alias:
npx emulate start --portless
# github https://github.emulate.localhost# google https://google.emulate.localhost# ...
This requires the portless proxy to be running (portless proxy start). If portless is not installed, emulate will prompt to install it.
The --portless flag overwrites any existing portless aliases matching *.emulate. Aliases are removed automatically when emulate shuts down.
For a custom base URL without portless (any reverse proxy):
npx emulate start --base-url "https://{service}.myproxy.test"# or
EMULATE_BASE_URL="https://{service}.myproxy.test" npx emulate start
The PORTLESS_URL env var is automatically set by the portless CLI wrapper when running a command through it (e.g. portless github.emulate emulate start), typically to a value like https://{service}.emulate.localhost. It supports {service} interpolation, just like --base-url and EMULATE_BASE_URL. When no explicit baseUrl is provided, it is used as a fallback.
Per-service overrides in the seed config (these take highest priority over all other base URL sources):
Then use these in your app to construct API and OAuth URLs. See each service's skill for SDK-specific override instructions.
Framework Integration (Embedded Mode)
The @emulators/adapter-next package embeds emulators directly into a Next.js app on the same origin. See the next skill (skills/next/SKILL.md) for full setup, Auth.js configuration, persistence, and font tracing details.
The @emulators/adapter-nuxt package embeds emulators directly into a Nuxt app on the same origin. See the nuxt skill (skills/nuxt/SKILL.md) for the server route, Nuxt config, OAuth configuration, and persistence setup.
Persistence
By default, all emulator state is in-memory. For persistence across process restarts and serverless cold starts, use a PersistenceAdapter.
Built-in file persistence
import { filePersistence } from'@emulators/core'// CLI or local dev: persists to a JSON fileconst adapter = filePersistence('.emulate/state.json')
State is loaded on cold start and saved after every mutating request (POST, PUT, PATCH, DELETE). Saves are serialized to prevent race conditions. Generated GitHub App identities require initialize to atomically create the initial value or return the value another instance created first.
Architecture
packages/
emulate/ # CLI entry point + programmatic API
@emulators/
core/ # HTTP server, Store, plugin interface, middleware
adapter-next/ # Next.js App Router integration
adapter-nuxt/ # Nuxt server route integration
vercel/ # Vercel API service plugin
github/ # GitHub API service plugin
google/ # Google OAuth 2.0 / OIDC plugin
slack/ # Slack Web API, OAuth, incoming webhooks plugin
linear/ # Linear GraphQL API, OAuth, webhooks plugin
twilio/ # Twilio Messaging, Verify, Voice, webhooks plugin
apple/ # Sign in with Apple / OIDC plugin
microsoft/ # Microsoft Entra ID OAuth 2.0 / OIDC plugin
aws/ # AWS S3, SQS, IAM, STS plugin
The core provides a generic Store with typed Collection<T> instances supporting CRUD, indexing, filtering, and pagination. Each service plugin registers routes with the shared internal app and uses the store for state.