Skip to main content

Credentials

A stage declares which secrets it needs. FlowWright resolves them immediately before the stage runs, injects them, and cleans up afterwards. The pipeline file names secrets; it never contains them.

stage("Publish", {
credentials: ["npm-token"],
run: async () => {
await sh.raw('npm config set //registry.npmjs.org/:_authToken "$NPM_TOKEN"');
await sh(["npm", "publish"]);
},
});

A bare string is the short form for a text secret bound to a derived environment variable.

Derived variable names

The base name comes from the credential id: non-alphanumeric runs become _, then uppercase.

Credential idBase
npm-tokenNPM_TOKEN
registryREGISTRY
aws.deploy.keyAWS_DEPLOY_KEY

The four types

stage("Deploy", {
credentials: [
"npm-token",
{ id: "registry", as: "usernamePassword" },
{ id: "gcp-sa", as: "secretFile" },
{ id: "deploy-key", as: "sshPrivateKey" },
],
run: async () => {},
});
TypeEnvironmentWhat's in it
secretText (default)BASEthe value
usernamePasswordBASE_USERNAME, BASE_PASSWORDthe values
secretFileBASEa path
sshPrivateKeyBASE, optionally a passphrase variablea path
_USERNAME and _PASSWORD, not _USER / _PASS

{ id: "registry", as: "usernamePassword" } binds REGISTRY_USERNAME and REGISTRY_PASSWORD. The shorter forms are the most common wrong guess, and they silently expand to nothing.

File credentials hold a path, not the contents

secretFile and sshPrivateKey write the secret to a temporary file with mode 0600 and put that file's path in the variable.

cat "$GCP_SA" # correct — reads the credential
echo "$GCP_SA" # prints /tmp/…, not the secret
gcloud auth activate-service-account --key-file "$GCP_SA" # what you usually want

Choosing your own names

credentials: [
{ id: "npm-token", env: "NODE_AUTH_TOKEN" },
{ id: "registry", as: "usernamePassword", usernameEnv: "DOCKER_USER", passwordEnv: "DOCKER_PASS" },
{ id: "deploy-key", as: "sshPrivateKey", env: "SSH_KEY_PATH", passphraseEnv: "SSH_PASSPHRASE" },
];

Useful when a tool expects a specific variable — NODE_AUTH_TOKEN for npm, DOCKER_USERNAME for a registry login.

Two credentials in one stage can't claim the same variable; flow validate rejects that with duplicate_credential_env.

Scope and lifetime

  • Resolved just before the declaring stage, never earlier.
  • Visible only to that stage. Another stage that needs the same secret declares it again.
  • Temporary files are deleted when the stage ends — success, failure or cancellation.
  • Values are registered with the log redactor, so an accidental echo is masked in stored output.
  • Resolution failure fails the stage closed, without echoing what went wrong.

In container stages, file credentials are re-pointed at a path inside the container, so the same variable works in both places.

Local runs

The CLI has no credential resolver — there's no local secret store to resolve against. Declaring credentials is what makes a pipeline portable to a server, where resolution happens; locally, supply secrets through your own environment and read them in commands as usual.

Declared credentials still show up in the plan, so flow validate checks the bindings and flow explain shows what a stage will ask for.

On a self-hosted deployment, resolution is the worker's job — it happens just-in-time, immediately before the declaring stage, and external providers are configured in the worker's own config file. See Worker.