SWIRLS_
Connections

Secrets

Declare secret names in the file (including vendor API keys), set values in the encrypted project vault, or use type: managed for Enterprise platform keys.

What it is. A named group of sensitive values your workflows need: API keys, tokens, credentials. The file declares the variable names; the values live in the project vault, never in the file — unless you use type: managed so Swirls supplies Enterprise platform keys.

Use it when a node calls a service that needs a key you hold, several workflows share the same credentials, or you want Enterprise platform-managed vendor keys declared in DSL.

Works with credential profiles (auth blocks that read values from a secret block), agents (every agent block references a secret block for its model key), context.secrets in @ts code, and the per-node secrets: map below.

User-defined secrets flow through context.secrets. Vendor integrations (AI, Resend, Firecrawl, Parallel) resolve their API keys internally from declared secret blocks; you do not read those keys from context.secrets in @ts blocks unless you also list them on the node secrets: map.

secret

Group related secret variable names (not values) in a top-level block. Values are set out-of-band in the project vault; no value ever appears in a .swirls file or a deployment.

FieldTypeRequiredDescription
labelstringNoDisplay label.
descriptionstringNoDescription.
typeidentifierNoOnly managed — platform supplies values (Enterprise). Omit for user vault values.
varsidentifier arrayYesSecret key identifiers (e.g. API_KEY, OPENROUTER_API_KEY).
secret api_k {
  label: "Third-party API"
  vars: [API_KEY, API_SECRET]
}

secret llm_keys {
  type: managed
  vars: [OPENROUTER_API_KEY]
}

Block names and var names match ^[a-zA-Z0-9_]+$. Repeating a var within one block is an error. Managed blocks may only list known platform vendor keys.

The project vault

Each project has its own vault. Values are encrypted at rest with per-project keys, and the vault is write-only: no CLI command, API route, or Portal page ever returns a stored value. Listings show whether a value is set, never what it is.

Set values with the swirls secret commands or on the project's Secrets page in the Portal:

CommandBehavior
swirls secret set KEY=VALUEStores the value as block::VAR for each matching non-managed secret block var. Rejects managed vars.
swirls secret listLists the vault's keys and whether a value is set. Alias: ls.
swirls secret remove KEYDeletes the stored value. Alias: rm.

All three take --project to target a project explicitly. If the same var name is declared in more than one block, swirls secret set writes every matching non-managed target and reports each.

Managed blocks show as "Managed by Swirls" on the Secrets page — no value input is offered.

Node-level secrets:

On root { } or node name { }, list which vars from which blocks this node may access:

workflow example {
  label: "Example"
  root {
    type: code
    label: "Entry"
    secrets: {
      api_k: [API_KEY]
    }
    code: @ts {
      const key = context.secrets.api_k.API_KEY
      return { hasKey: Boolean(key) }
    }
  }
}

Access pattern: context.secrets.<blockName>.<VAR>. See Context. The secrets: value is always an object literal, never a bare block name, a string, or a flat array. There is no process.env in @ts code; it is an empty object in the sandbox.

A node sees only the vars it declared. Secrets are delivered at run time, per node, so a workflow's blast radius is exactly what its file says it is.

Who references a secret block

ConsumerSyntaxMeaning
Any nodesecrets: { <block>: [VAR, ...] }Allowlist of vars the node may read via context.secrets.
auth / postgres blocksecrets: <block> (bare identifier)The single block whose vars back the credential fields.
agent blocksecrets: <block> (bare identifier, required)Block holding the model API key and any agent credentials.
webhook blocksecret: <block>.<VAR> (dotted reference)Shared-secret value compared against the inbound header:.

The validator checks that every referenced block exists and every listed var is declared in it.

Required vendor keys

Node types that call third-party APIs need the corresponding key declared in some secret block (user or type: managed):

Node typeRequired secret
ai, agentOPENROUTER_API_KEY, or OPENAI_API_KEY / ANTHROPIC_API_KEY / GOOGLE_GENERATIVE_AI_API_KEY per provider:
emailRESEND_API_KEY
scrape, searchFIRECRAWL_API_KEY
parallelPARALLEL_API_KEY
diskARCHIL_API_KEY (platform-only; never declared in DSL)

Until a required key is declared and satisfiable (vault value set, or managed + Enterprise), executions for the nodes that need it are held with secrets_hold. They pick up the fix on the next run after you update the DSL / vault / plan.

Further reading

  • Contextcontext.secrets shape
  • Auth — credential profiles built on secret blocks

On this page