emulate

작성자: vercel

Vercel, GitHub, Google, Slack, Apple, Microsoft, AWS를 위한 로컬 드롭인 API 에뮬레이터입니다. 사용자가 에뮬레이션된 서비스를 시작하거나 시드를 구성해야 할 때 사용하세요.

npx skills add https://github.com/vercel-labs/emulate --skill 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:

ServiceDefault Port
Vercel4000
GitHub4001
Google4002
Slack4003
Apple4004
Microsoft4005
Okta4006
AWS4007
Resend4008
Stripe4009
MongoDB Atlas4010
Clerk4011
Linear4012
Twilio4013

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 a starter config
npx emulate init

# Generate config for a specific service
npx emulate init --service vercel

# List available services
npx emulate list

Options

FlagDefaultDescription
-p, --port4000Base port (auto-increments per service)
-s, --serviceallComma-separated services to enable
--seedauto-detectPath to seed config (YAML or JSON)
--base-urlnoneOverride advertised base URL (supports {service} template)
--portlessoffServe over HTTPS via portless (auto-registers aliases)

The port can also be set via EMULATE_PORT or PORT environment variables.

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:

import { createEmulator } from 'emulate'

const github = await createEmulator({ service: 'github', port: 4001 })
const vercel = await createEmulator({ service: 'vercel', port: 4002 })

github.url   // 'http://localhost:4001'
vercel.url   // 'http://localhost:4002'

await github.close()
await vercel.close()

Options

OptionDefaultDescription
service(required)'vercel', 'github', 'google', 'slack', 'apple', 'microsoft', 'okta', 'aws', 'resend', 'stripe', 'mongoatlas', 'clerk', 'linear', or 'twilio'
port4000Port for the HTTP server
seednoneInline seed data (same shape as YAML config)
baseUrlnoneOverride 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>.

Instance Methods

MethodDescription
urlBase URL of the running server
reset()Wipe the store and replay seed data
close()Shut down the HTTP server, returns a Promise

Vitest / Jest Setup

import { createEmulator, type Emulator } from 'emulate'

let github: Emulator
let vercel: Emulator

beforeAll(async () => {
  ;[github, vercel] = await Promise.all([
    createEmulator({ service: 'github', port: 4001 }),
    createEmulator({ service: 'vercel', port: 4002 }),
  ])
  process.env.GITHUB_EMULATOR_URL = github.url
  process.env.VERCEL_EMULATOR_URL = vercel.url
})

afterEach(() => { github.reset(); vercel.reset() })
afterAll(() => Promise.all([github.close(), vercel.close()]))

Configuration

Configuration is optional. The CLI auto-detects config files in this order:

  1. emulate.config.yaml / .yml
  2. emulate.config.json
  3. service-emulator.config.yaml / .yml
  4. service-emulator.config.json

Or pass --seed <file> explicitly. Run npx emulate init to generate a starter file.

Config Structure

tokens:
  my_token:
    login: admin
    scopes: [repo, user]

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
  integrations:
    - client_id: oac_abc123
      client_secret: secret_abc123
      name: My Vercel App
      redirect_uris:
        - http://localhost:3000/api/auth/callback/vercel

github:
  users:
    - login: octocat
      name: The Octocat
      email: octocat@github.com
  orgs:
    - login: my-org
      name: My Organization
  repos:
    - owner: octocat
      name: hello-world
      language: JavaScript
      auto_init: true
  oauth_apps:
    - client_id: Iv1.abc123
      client_secret: secret_abc123
      name: My Web App
      redirect_uris:
        - http://localhost:3000/api/auth/callback/github

google:
  users:
    - email: testuser@example.com
      name: Test User
  oauth_clients:
    - client_id: my-client-id.apps.googleusercontent.com
      client_secret: GOCSPX-secret
      redirect_uris:
        - http://localhost:3000/api/auth/callback/google

slack:
  team:
    name: My Workspace
    domain: my-workspace
  users:
    - name: developer
      real_name: Developer
      email: dev@example.com
  channels:
    - name: general
      topic: General discussion
  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

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
  issues:
    - team: ENG
      title: Fix local checkout test
      state: Todo
      assignee: dev@example.com
  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]
  tokens:
    - token: lin_test_admin
      user: admin@example.com
      scopes: [read, write, issues:create, comments:create, admin]

apple:
  users:
    - email: testuser@icloud.com
      name: Test User
  oauth_clients:
    - client_id: com.example.app
      team_id: TEAM001
      name: My Apple App
      redirect_uris:
        - http://localhost:3000/api/auth/callback/apple

microsoft:
  users:
    - email: testuser@outlook.com
      name: Test User
  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

aws:
  region: us-east-1
  s3:
    buckets:
      - name: my-app-bucket
  sqs:
    queues:
      - name: my-app-events
  iam:
    users:
      - user_name: developer
        create_access_key: true
    roles:
      - role_name: lambda-execution-role

Auth

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 single service behind portless:

portless github.emulate emulate start --service github

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):

github:
  baseUrl: https://github.emulate.localhost
google:
  baseUrl: https://google.emulate.localhost

Pointing Your App at the Emulator

Set environment variables to override real service URLs:

VERCEL_EMULATOR_URL=http://localhost:4000
GITHUB_EMULATOR_URL=http://localhost:4001
GOOGLE_EMULATOR_URL=http://localhost:4002
SLACK_EMULATOR_URL=http://localhost:4003
APPLE_EMULATOR_URL=http://localhost:4004
MICROSOFT_EMULATOR_URL=http://localhost:4005
AWS_EMULATOR_URL=http://localhost:4007
LINEAR_EMULATOR_URL=http://localhost:4012

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 file
const adapter = filePersistence('.emulate/state.json')

Custom adapters

import type { PersistenceAdapter } from '@emulators/core'

const kvAdapter: PersistenceAdapter = {
  async load() { return await kv.get('emulate-state') },
  async save(data) { await kv.set('emulate-state', data) },
}

State is loaded on cold start and saved after every mutating request (POST, PUT, PATCH, DELETE). Saves are serialized to prevent race conditions.

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.

vercel의 다른 스킬

benchmark-sandbox
vercel
Vercel Sandbox에서 vercel-plugin eval 시나리오를 로컬 WezTerm 패널 대신 실행합니다. Claude Code와 플러그인이 사전 설치된 임시 마이크로VM을 프로비저닝합니다.
official
emil-design-eng
vercel
이 스킬은 Emil Kowalski의 UI 폴리시, 컴포넌트 디자인, 애니메이션 결정, 그리고 소프트웨어를 훌륭하게 만드는 보이지 않는 세부 사항에 대한 철학을 인코딩합니다.
official
vercel-react-best-practices
vercel
Vercel Engineering의 React 및 Next.js 성능 최적화 가이드라인입니다. 이 스킬은 React/Next.js 코드를 작성, 검토 또는 리팩토링할 때 사용해야 합니다.
official
vercel-react-best-practices
vercel
Vercel Engineering의 React 및 Next.js 성능 최적화 가이드라인입니다. 이 스킬은 React/Next.js 코드를 작성, 검토 또는 리팩토링할 때 사용해야 합니다.
official
write-guide
vercel
점진적인 예제를 통해 실제 사용 사례를 가르치는 기술 가이드를 제작합니다. 개념은 독자가 필요로 할 때만 소개됩니다.
official
release
vercel
Vercel-plugin 릴리스 — 게이트 실행, 버전 업, 아티팩트 생성, 커밋 및 푸시. "릴리스", "배포", "버전 업 및 푸시", "릴리스 생성" 요청 시 사용.
official
deepsec
vercel
dev3000에서 체크아웃한 Vercel 프로젝트에 대해 DeepSec을 실행합니다. 원클릭 DeepSec 설정, 프로젝트 컨텍스트 부트스트래핑, 제한된 1차 처리 등에 사용합니다.
official
backport-pr
vercel
병합된 Next.js 풀 리퀘스트를 canary에서 next-16-2와 같은 이전 릴리스 브랜치로 백포트합니다. 사용자가 백포트, 체리픽 또는 열기를 요청할 때 사용합니다…
official