Skip to content

Environments

One Chaski Worker per environment of your app, each with resources of its own, from one project.

Each environment of your app, such as production and staging, gets a Chaski Worker of its own, with its own database, queue, dashboard and channel settings. One Chaski project deploys them all: the top of its wrangler.jsonc is production, as Install sets it up, and every other environment is a block under env.

Add an environment

In the Chaski project:

Terminal
npx chaskijs env add staging --public-url https://staging.example.com/me/notifications

It adds an env.staging block to wrangler.jsonc. Wrangler doesn’t carry bindings or vars from the top of the file into an environment, so the block repeats each one, with that environment’s names:

wrangler.jsonc
{
  "name": "chaski",
  // …production, as Install sets it up
  "env": {
    "staging": {
      "vars": {
        "CHASKI_ENVIRONMENT": "staging",
        "CHASKI_PUBLIC_URL": "https://staging.example.com/me/notifications"
      },
      "d1_databases": [
        {
          "binding": "CHASKI_DB",
          "database_name": "chaski-staging",
          "database_id": "local",
          "migrations_dir": "node_modules/chaskijs/migrations"
        }
      ],
      "queues": {
        "producers": [{ "binding": "CHASKI_QUEUE", "queue": "chaski-staging-deliveries" }],
        "consumers": [
          {
            "queue": "chaski-staging-deliveries",
            "max_batch_size": 10,
            "max_batch_timeout": 1,
            "max_retries": 5,
            "dead_letter_queue": "chaski-staging-deliveries-dlq"
          }
        ]
      },
      "durable_objects": {
        "bindings": [
          { "name": "CHASKI_FEED", "class_name": "ChaskiFeed" },
          { "name": "CHASKI_EVENTS", "class_name": "ChaskiEvents" }
        ]
      },
      "workflows": [
        {
          "name": "chaski-staging-scheduler",
          "binding": "CHASKI_SCHEDULER",
          "class_name": "ChaskiScheduler"
        }
      ],
      "send_email": [{ "name": "CHASKI_EMAIL" }]
    }
  }
}

Wrangler names the Worker chaski-staging, after the top-level name and the environment, and every resource follows: the database chaski-staging, the queue chaski-staging-deliveries. The Workflow needs a name of its own in every environment, since its name is unique in your account.

Deploy it

Terminal
npx chaskijs deploy --env staging

It does for staging what it does for production: creates the resources staging is missing, writes its database’s id, applies the migrations, and deploys chaski-staging with a CHASKI_SECRET of its own. Each step runs the Wrangler command with --env staging. By hand, the first deploy of chaski-staging takes its secret with npx wrangler deploy --env staging --secrets-file chaski-secret.env, as Install shows. A chaski-staging that already runs without the secret gets it with npx wrangler secret put CHASKI_SECRET --env staging, after a deploy: until the Worker exists, secret put creates an empty one under its name.

Then turn on Cloudflare Access for its URL and set up its channels in its own dashboard, as Install does for production. Settings never move between environments: staging can send from a test domain while production sends from your own.

Bind each app environment to its Chaski

Your app’s staging environment binds to chaski-staging, and its production to chaski:

wrangler.jsonc (your app)
{
  "services": [{ "binding": "CHASKI", "service": "chaski", "entrypoint": "ChaskiEntrypoint" }],
  "env": {
    "staging": {
      "services": [
        { "binding": "CHASKI", "service": "chaski-staging", "entrypoint": "ChaskiEntrypoint" }
      ]
    }
  }
}

The code doesn’t change: it calls env.CHASKI in every environment, and each one reaches its own Chaski.

Keep them in step

An upgrade goes to every environment the same way, staging first:

Terminal
npx chaskijs upgrade
npx chaskijs deploy --env staging
npx chaskijs deploy

upgrade installs the latest chaskijs and brings wrangler.jsonc and the main module, in every environment, up to what that version needs, such as a Durable Object migration for a class it added. Each deploy then applies the new migrations before the new code. The dashboard’s header names the environment from CHASKI_ENVIRONMENT, so nobody mistakes one for the other.

Updated Oct 30, 2026

MIT License · chaski.sh