Skip to main content

qfg run — inject Quonfig values as env vars

qfg run resolves Quonfig configs into environment variables and execs a child process. Use it for anything that reads its config from process.env before user code runs and therefore can't call the SDK directly.

Concrete examples:

  • drizzle-kit migrate reads DATABASE_URL at module import.
  • next build and other build steps consume env vars during the build pipeline.
  • next-auth resolves AUTH_SECRET at boot, before your application code initializes.
  • One-shot scripts that you don't want to wrap in an SDK lifecycle.

For long-running services (Next.js servers, API workers, etc.) prefer initializing the SDK directly — see qfg run vs SDK init below.

Syntax​

Two ways to specify the env-var-to-config mapping. Both forms require the -- separator between qfg run flags and the child command.

Inline --env​

qfg run --env DATABASE_URL=db.url -- drizzle-kit migrate

--env is repeatable. Each value takes the form VAR=key.path, where VAR is the environment variable name the child will see and key.path is the Quonfig config key.

--env-file​

qfg run --env-file=.qfg.env -- next build

The file holds one VAR=key.path per line. Blank lines and # comments are skipped.

# .qfg.env
AUTH_SECRET=auth.secret
DATABASE_URL=db.url
STRIPE_API_KEY=stripe.api.key

The -- separator​

The -- between Quonfig flags and the child command is required. Without it, oclif eats child flags that look like Quonfig flags (e.g. --silent).

qfg run --env DATABASE_URL=db.url -- drizzle-kit migrate    # OK
qfg run --env DATABASE_URL=db.url drizzle-kit migrate # not parsed as a child command

package.json examples​

This is what most users will copy/paste:

{
"scripts": {
"db:migrate": "qfg run --env DATABASE_URL=db.url -- drizzle-kit migrate",
"build": "qfg run --env-file=.qfg.env -- next build"
}
}

Chaining commands​

qfg run resolves once per invocation. To amortize one resolve across multiple steps, run them under a single shell:

qfg run --env-file=.qfg.env -- bash -c "npm run db:migrate && npm run build"

Auth and environment — pick exactly one mode​

qfg run uses one of two mutually exclusive auth/env modes. The rule is binary on purpose: tolerating "they happen to agree" lets a stale env var quietly drift past you until the day it disagrees in CI.

Mode A — SDK key​

Set QUONFIG_BACKEND_SDK_KEY. The SDK key encodes both the workspace and the environment, so do not also set QUONFIG_ENVIRONMENT or pass --environment.

export QUONFIG_BACKEND_SDK_KEY=qfg_sk_…
qfg run --env DATABASE_URL=db.url -- drizzle-kit migrate

This is the typical CI / Docker mode: the deploy pipeline injects QUONFIG_BACKEND_SDK_KEY, and qfg run evaluates against the environment that key was minted for.

Mode B — User auth​

After qfg login, set exactly one of QUONFIG_ENVIRONMENT (env var) or --environment (flag). Use this for local development against your own account.

qfg login
qfg run --env DATABASE_URL=db.url --environment=staging -- drizzle-kit migrate

or

qfg login
export QUONFIG_ENVIRONMENT=staging
qfg run --env DATABASE_URL=db.url -- drizzle-kit migrate

Errors you'll see when you cross the streams​

If you set QUONFIG_BACKEND_SDK_KEY and also pass --environment or set QUONFIG_ENVIRONMENT:

qfg run: QUONFIG_BACKEND_SDK_KEY is set, which encodes the environment.
Remove --environment and unset QUONFIG_ENVIRONMENT, or remove the SDK key.

If you have no SDK key and have set both --environment and QUONFIG_ENVIRONMENT:

qfg run: pass exactly one of --environment or QUONFIG_ENVIRONMENT (both are set).

If you have no SDK key and have set neither:

qfg run: no environment specified.
Either set QUONFIG_BACKEND_SDK_KEY (which encodes env) or
set QUONFIG_ENVIRONMENT / pass --environment after `qfg login`.

package.json portability gotcha​

If your repo's package.json has qfg run baked into a script, the script must work in every environment that runs it — laptop, CI, Docker. The trap: most monorepos set QUONFIG_ENVIRONMENT for long-running services so the SDK knows which environment to evaluate. A CI Dockerfile that uses an SDK key for qfg run must NOT also set QUONFIG_ENVIRONMENT — qfg run will fail with the ambiguous-mode error above, even though the same env var is correct for the running app.

The cleanest pattern is to leave QUONFIG_ENVIRONMENT unset in build/migrate steps and let the SDK key carry the environment.

qfg run vs SDK init​

Use qfg run for one-shot work where there's no long-running process:

  • Build steps (next build, vite build, …)
  • Migrations (drizzle-kit migrate, prisma migrate deploy, rails db:migrate)
  • One-off scripts and admin commands

Use SDK init (Next.js instrumentation.ts, an explicit Quonfig client in your server bootstrap, etc.) for long-running services. The SDK keeps an SSE connection open and applies live config updates without a restart, which qfg run cannot do — it resolves once at process start.

Some apps will use both: qfg run for the build/migrate steps in CI, SDK init for the running server.

Override behavior​

By default, values resolved by qfg run override matching env vars in the parent shell. The child process sees the Quonfig-resolved value even if DATABASE_URL was already exported.

This default is deliberate: most users invoke qfg run because they want Quonfig to be the source of truth. Falling back to the parent env silently would mean a half-set local shell could mask production values without warning.

If you want the opposite — keep parent env where set, only fill in the gaps — pass --preserve-env:

qfg run --env DATABASE_URL=db.url --preserve-env --environment=staging -- npm test

Security note​

Values resolved by qfg run end up in the child's environment. They're visible to that process via process.env and to anything inside the process via printenv//proc/self/environ. This is the same threat model as any env-var-based secret injection — qfg run doesn't change it.

Practical rules:

  • Don't pipe qfg run output into chat, logs, or CI artifacts in ways that would reveal resolved values.
  • The child process can leak its env in stack traces, crash dumps, and debug endpoints. Treat it as such.
  • For the most sensitive secrets, prefer the encrypted-secret pattern documented in Secret Management — Quonfig stores ciphertext, the SDK decrypts in-process, and the plaintext never lands in printenv-visible env vars.