Skip to content

Variables & secrets

Every project has a Variables & Secrets panel on its page in the console (app.qubepods.com). Values are scoped to the project: every application deployed in the project reads the same set, and other projects — including your own staging project — see none of it.

Plain, non-sensitive configuration: base URLs, feature flags, tuning values.

  • Keys look like env vars: letters, digits, underscores (API_BASE_URL).
  • Values are visible and editable in the console — use them for anything you’d be comfortable committing to a config file.

API keys, connection strings, signing keys — anything sensitive.

  • Write-only. You set a value once; after that the console shows only the name and when it changed. You can replace a value or delete the secret, but never view it again — copy it from the source if you need it elsewhere. (While typing or pasting a new value, the eye icon lets you check it — up until you save.)
  • Encrypted at rest. Values are envelope-encrypted before they touch the database (AES-256-GCM, a distinct key per project), so they are never legible in storage, backups, or admin tooling.

Your qube names the values it needs in qube.json5 — names only, never values (manifests live in git):

imports: {
variables: [{ name: "GREETING" }], // -> env.GREETING
secrets: [{ name: "SESAME_PASSWORD" }], // -> env.SESAME_PASSWORD
}

Your code then simply reads them off env — nothing to fetch, nothing to decrypt:

export default {
async fetch(request, env) {
env.GREETING // the variable's value
env.SESAME_PASSWORD // the secret's value
}
}

The declaration buys you two guarantees:

  1. Deploy-time validation. If a declared value isn’t set on the project, qube deploy refuses — before anything goes live — and names exactly what’s missing:

    this qube requires variable(s) GREETING and secret(s) SESAME_PASSWORD —
    not set for this project. Set them in the console
    (Project → Variables & Secrets), then redeploy.
  2. Least privilege. Only declared names are injected. A project value your manifest doesn’t name is invisible to your qube.

An optional binding renames a value inside the qube: { name: "API_KEY", binding: "UPSTREAM_KEY" } → env.UPSTREAM_KEY.

Values are resolved fresh on every deploy or promote — change or delete one in the console, redeploy, and the change rides along. Working example: open-sesame, live at open-sesame.qubepod.app.

Because variables and secrets are per-project, the two-project staging pattern gets isolation for free: put the test-mode API key in the stage project and the live key in the prod project — same code, same variable names, different values, no way to cross them.

  • Reading the panel — any member of the project.
  • Adding, editing, deleting — project admins only.
  • Secret values are never returned by the API to anyone, admins included.