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.json5names 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.