Skip to content

Running twins locally

The first step before wiring your app: get a single twin running on your machine and confirm it’s reachable.

  • wt CLI installed (see the wondertwin repo for install instructions)
  • You know which vendor you want to twin (e.g. Stripe, Plaid, PostHog)
  • The vendor is in the twin catalog (or queued via Wishlist)
Terminal window
# Initialize a new twin (downloads the vendor's twin package locally)
npx wondertwin init stripe
# Start it
wt up stripe
# Verify it's running and on what port
wt status

Expected output:

1 twin running
✓ Stripe twin v3.2 ready on localhost:4111 · drift-aligned · 0 errors

The default port assignment is deterministic per vendor (Stripe → :4111, Plaid → :4112, etc.); wt status prints the actual port. Override with wt up stripe --port 5000 if you need a non-default.

The twin speaks the real vendor’s API surface on the assigned port. Use the vendor’s SDK or curl exactly as you would against the real service — just change the base URL.

Terminal window
# Real Stripe
curl https://api.stripe.com/v1/charges -u "$STRIPE_KEY:"
# Local Stripe twin
curl http://localhost:4111/v1/charges -u "$STRIPE_KEY:"

The next section (app-against-local-twins) covers the canonical pattern for doing this substitution in application code instead of curl.

Terminal window
wt down stripe # one twin
wt down --all # everything currently running
Terminal window
wt up stripe plaid posthog
wt status

Each twin runs in its own process; wt up is idempotent (calling it on an already-running twin is a no-op).

This step covers the bottom-left of the substitution model: you’ve started a local twin (red layer) but your application is not yet talking to it. Step 2 wires that up.

  • Troubleshooting common startup failures (port conflicts, license-check errors, missing reference data)
  • wt logs <vendor> for tailing twin output
  • Persistence between wt down / wt up cycles
  • Snapshotting / replay flags