Skip to content

Environments & deploy

Every Muhkoo app has two environments — test and production — in one app. Deploy changes to test, exercise them without touching the live app, then promote test → production in place. There’s no second app to manage and no risk of editing production by accident.

The environment is decided by the key. Each app issues two key pairs:

KeyEnvironmentUse
mk_test_pk_… / mk_test_sk_…testthe publishable key in your test build; the secret key for test deploys
mk_live_pk_… / mk_live_sk_…productionthe publishable key in your production build; the secret key for production deploys

A pk (publishable) key goes in the client; a sk (secret) key authorizes deploys and never ships to the browser. Deploy with a test secret key and it lands in test; deploy with a live secret key and it lands in production.

Test is served at <slug>.test.apps.muhkoo.dev, production at <slug>.apps.muhkoo.dev.

The two environments are fully isolated, so working in test never disturbs production:

  • Hosting — each env has its own release history and live pointer.
  • Serverless functions — each function exists independently in test and production.
  • Config — allowed origins and hosted-auth redirect URIs are per-env (test and production usually run on different hostnames).
  • Data — the database tables, channels, and logs are already per-env, so your test data is separate from real user data.

The only thing that differs between builds is the publishable key (and the API base, if you target staging). Keep a committed env file per environment — publishable keys and URLs are public:

.env.test
MUHKOO_KEY=mk_test_pk_…
.env.production
MUHKOO_KEY=mk_live_pk_…
# MUHKOO_BASE_URL is optional — it defaults to the hosted accelerator
# (https://api.muhkoo.dev), so production usually doesn't set it.
const client = new Client({
apiKey: process.env.MUHKOO_KEY,
baseUrl: process.env.MUHKOO_BASE_URL, // optional; defaults to the hosted accelerator
});

muhkoo deploy ships your built dist/ to hosting. It deploys to test by default (using the test secret key from .muhkoo-app.json). Pass a live secret key to deploy to production:

Terminal window
muhkoo deploy # → test (<slug>.test.apps.muhkoo.dev)
muhkoo deploy --key "$MUHKOO_LIVE_SK" # → production (<slug>.apps.muhkoo.dev)

Or deploy to test, then promote the tested release to production in place:

Terminal window
muhkoo deploy # → test
muhkoo promote # test → production (hosting + functions)

Build the client against the matching env file first, so the right publishable key is baked in. See the CLI guide.

The portal has an environment selector on the app’s Deploy tab — upload a build, roll back, or manage the live pointer for either environment.

When test looks right, promote it — production is updated in place; there’s no separate production deploy to repeat:

  1. Run muhkoo promote from the app dir, or open the app’s Environments pipeline in the portal and click Promote to production.
  2. The current test hosting release is copied to production and the production pointer flips atomically. Functions are promoted too (upserted by name).

Config is intentionally not promoted — allowed origins and redirect URIs are per-environment by design, because test and production run on different hostnames. Set those once per env in the portal. Production data is never touched by a promote.

Point each environment at its own hostname through the portal’s domain settings — e.g. app.example.com for production and app-test.example.com for test — and make sure TLS is provisioned for each before going live.

Keys are issued when you create the app — in the portal or with muhkoo provision, which writes all four into .muhkoo-app.json. Rotate the whole set any time with muhkoo keys rotate <appId>. Because keys are environment-bound, a test key returns API key required against production and vice-versa — if auth or messaging 401s, check you’re using the key for the right environment.