Heroku

Lightweight, dependency-free, in-memory fake of the Heroku Platform API v3 for testing deploy/ops automation. Zero runtime dependencies (Node builtins only); state is in-memory and ephemeral.

Default port: 4883

Quick start

import { HerokuServer } from "./services/heroku/src/server.js";

const server = new HerokuServer(4883);
await server.start();
// ... run your app/tests ...
await server.stop();

Authenticate with Authorization: Bearer <key> and send the v3 Accept header (any non-empty key accepted):

curl -H "Authorization: Bearer parlel" \
     -H "Accept: application/vnd.heroku+json; version=3" \
     http://127.0.0.1:4883/apps

Access via MCP / preview URL

The service is registered in the parlel pool and reachable through the parlel MCP server and its generated preview URL. Set HEROKU_API_KEY=parlel and HEROKU_BASE_URL=http://127.0.0.1:4883, then drive the Platform API v3. The MCP server proxies the endpoints below so an agent can manage apps, config vars, and dynos without a real Heroku account.

Implemented operations

All endpoints (except /, /health) require Authorization: Bearer <key> (any non-empty key accepted). Clients should send Accept: application/vnd.heroku+json; version=3.

Service & inspection operations (parlel extensions)

Surface coverage

This emulator faithfully replicates the API surface most application code and agents exercise. Anything below the supported lines is either an intentional design choice for a fast, zero-cost local emulator (✓ By design) or a candidate for a future release (⟳ Roadmap) — never a silent inaccuracy.

Legend: ✅ fully supported · ◐ accepted (stored, not strictly enforced) · ✓ by design · ⟳ on the roadmap.

FeatureStatus
Apps create/list/get/update/delete (by id or name)✅ Supported
Config vars get/set/unset✅ Supported
Dynos list/create✅ Supported
Account get✅ Supported
Real build/release/slug pipeline⟳ Roadmap — Intentionally unsupported
Releases / formation / add-ons / pipelines / domains⟳ Roadmap
Range-based pagination (Range header)⟳ Roadmap — Full list returned
Dyno lifecycle (restart/stop, actual process)✓ By design — In-memory by design — fast, isolated, resets cleanly between tests
API key validity / scope enforcement✓ By design — Any non-empty credential is accepted — no real secrets needed

Manifest

See services/heroku/manifest.json:

<!-- parlel:testenv:start -->

Configuration — test.env

Copy these into your test.env (used by the bridge sidecar flow). Tokens are Parlel's seeded test credentials — any non-empty value is accepted by the emulator, so you rarely need to change them. Swap in real credentials only when pointing at the live service in prod.env.

HEROKU_API_KEY=parlel
HEROKU_BASE_URL=http://parlel-bridge:4883
<!-- parlel:testenv:end -->