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 id | Base |
|---|---|
npm-token | NPM_TOKEN |
registry | REGISTRY |
aws.deploy.key | AWS_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 () => {},
});
| Type | Environment | What's in it |
|---|---|---|
secretText (default) | BASE | the value |
usernamePassword | BASE_USERNAME, BASE_PASSWORD | the values |
secretFile | BASE | a path |
sshPrivateKey | BASE, optionally a passphrase variable | a 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.
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.