What localhost2137 is

What localhost2137 owns, what plugins own, and how an application interacts with both.

localhost2137 runs stateful emulator plugins for external developer services. An application talks to a plugin through its normal provider SDK or HTTP boundary. Tests, scripts, and developers control the same local world through typed operations or the CLI.

localhost.config.ts
import { slack } from "@localhost2137/slack";
import { defineConfig } from "localhost2137";

export default defineConfig({
	clock: { mode: "pinned", startAt: "2026-01-01T00:00:00.000Z" },
	services: {
		slack: slack({
			config: {
				botToken: "xoxb-local-crash-course",
				eventsUrl: null,
				signingSecret: "local-crash-course-signing-secret",
				workspaceName: "Local workspace",
			},
			seed: {
				users: [{ id: "U_ADA", name: "Ada" }],
				channels: [{ id: "C_GENERAL", name: "general", members: ["U_ADA"] }],
			},
		}),
	},
});
terminal 1
pnpm exec localhost dev
terminal 2
pnpm exec localhost run -- pnpm dev

The config mounts emulator code and optional local seed data. localhost dev hosts the configured services; localhost run -- starts the application with that instance's local URLs and fake credentials. Neither the developer nor a coding agent needs provider API keys for this local path. Getting started runs this exact config and shows what each command changes.

It is not a generic request/response mock server, and a plugin is not a local copy of an entire provider. Each plugin implements a bounded service contract: provider-shaped HTTP behavior, state, control operations, persistence, and any callback delivery it supports.

Two interfaces, one local world

Your application uses the plugin's provider-compatible HTTP API. Tests, scripts, developers, and coding agents use operations to arrange and inspect the same state.

application ── provider SDK / HTTP ──> emulated API
                                         │
test or agent ── typed operation / CLI ──┘

Operations can also trigger external actors and events. The interface a test should use depends on the behavior it claims to verify. Operations and emulated APIs follows that boundary through complete Slack and Stripe scenarios. Callbacks and webhooks explains the opposite HTTP direction: plugin delivery into the application, including signatures, retries, tracked work, and shared receiver constraints.

The service key in localhost.config.ts is the route, storage, CLI, and typed-handle identity. The dev Slack URL, for example, begins at http://127.0.0.1:2137/dev/slack.

When it fits

Use localhost2137 when the behavior under test depends on a service world changing over a sequence: an SDK call creates state, another call reads it, time advances, or an event reaches the application. A function fake or HTTP stub is usually simpler when the claim concerns one call and no meaningful service lifecycle. A provider sandbox or real service is still needed for claims about live infrastructure and unimplemented provider behavior.

Choose the right test boundary develops that decision from the defect a test must catch. Provider compatibility explains how to assess the narrower claims an installed plugin actually proves.

Ownership boundary

The runtime owns explicit instances, route mounting, lifecycle timing, isolated storage locations, operation adapters, generated connection values, virtual time, tracked async work, and control-plane authentication.

Each plugin owns service behavior, compatible responses, control operations, configuration, data format, migrations, retry rules, and persistence. This boundary is why localhost2137 can host a general plugin ecosystem without learning each provider's rules in its kernel.

The normal loop

  1. Configure installed plugins in ordinary TypeScript.
  2. Start localhost dev; it creates the persistent dev world empty only when it is absent. Later starts preserve that world until you reset it.
  3. Pass generated connection values to the application's existing SDK or service adapter.
  4. Arrange and inspect state through plugin operations.
  5. Exercise the application through its normal provider-facing boundary.
  6. Await tracked asynchronous work before asserting.
  7. Reset or destroy the world when it no longer matters.

Instances and isolation explains which resources belong to a world and which remain shared. In particular, instances do not create separate plugin configuration or callback URLs; before parallel event or webhook tests, read Callbacks and webhooks.

Continue by intent

The reference section is for exact behavior once a task raises a question: start with Configuration, CLI workflow and reference, or Runtime boundaries.