Runlane
ReferenceVocabulary

Identifiers

Public IDs, keys, names, and what each one is for.

Runlane's public identity values are opaque strings. Application code writes them as plain strings at authoring boundaries; Runlane validates and brands them before durable records, leases, schedules, and delivery messages are written.

Shared rules:

  • Values must be non-empty strings.
  • Values must not contain :.
  • Treat values as whole identifiers, not parseable prefix paths.
  • Use queues to route work; do not use worker IDs as routing targets.

: is reserved so storage adapters can compose their own backend-internal keys without colliding with public Runlane ids. Use dots, underscores, or a hashed segment for application structure:

NeedGoodRejected
Task idemails.welcomeemails:welcome
Idempotency keyemails.welcome.user_123emails:welcome:user_123
Singleton key from external idquickbooks_invoices_user_123quickbooks:invoices:user_123
Dynamic unsafe external idprovider_account_${hash(accountId)}Raw value that may contain : or unbounded text

Public Identity Values

Ideal owner names who should supply or manage the value in normal application code. Durable records and operator APIs may still expose values owned by Runlane.

ValueIdeal ownerWhat it namesWhat it is for
Task IDUser/app authorA stable task definition, such as emails.welcomeSelects the registered handler and schema. Do not put tenant, user, or resource IDs here.
Run IDRunlane by default; user/operator only for external correlationOne durable execution recordNames a specific run for operator reads or external correlation.
Schedule IDUser/app authorA registered schedule definitionDeduplicates and audits schedule materialization. Use one stable ID per logical schedule.
Queue nameUser/app deployment configA logical routing lane such as default, emails, or mediaSerializes a provider-neutral queue definition into durable records and transport envelopes.
Idempotency keyUser/app producer or task definitionOne logical trigger request for one task/environmentReturns the original active or retained terminal run for duplicate producer calls.
Singleton keyUser/app producer or task definitionOne active resource that must not overlapPrevents concurrent active runs for the same resource.
Concurrency keyUser/app producer or task definitionOne bounded-queue capacity partitionLimits execution concurrency per tenant, account, or resource without deduplicating trigger requests.
Worker IDRunlane by default; user config only for diagnosticsThe process or invocation that claimed workRecords diagnostic ownership for leases, schedule claims, and outbox claims. It does not route work.

Common authoring locations include:

  • Task and schedule identity: task({ id }) and task({ schedule: { id } }).
  • Queue routing: queue({ name }), task({ queue }), trigger/runNow queue options, and worker queue filters.
  • Run creation keys: static task({ idempotencyKey, singletonKey, concurrencyKey }) values, task key resolvers, and explicit trigger() or runNow() options.
  • Run and worker identity: trigger(..., { runId }), runNow(..., { runId, workerId }), createRunlane({ workerId }), worker({ workerId }), executeNext({ workerId }), and executeDelivery(..., { workerId }).

environment.name is also public, but it is a namespace rather than a Runlane ID. It scopes durable records so development, staging, production, tenants, or test suites do not see each other's runs.

Choosing The Right Value

When deciding where a value belongs:

  • If it names the kind of work, use the task ID.
  • If it chooses which worker pool should process the work, use a queue definition.
  • If it deduplicates a producer retry or returns a retained terminal owner, use the idempotency key. Repeat triggers with the same retained idempotency key return the original run.
  • If it prevents overlap for one resource, use the singleton key.
  • If every request should become a run but execution must be limited by partition, use the concurrency key on a bounded queue.
  • If it identifies one execution record, use the run ID.
  • If it identifies recurring materialization, use the schedule ID.
  • If it identifies who claimed work, use the worker ID and keep it out of producer routing logic.

Runlane idempotency keys with a finite idempotencyKeyTTL are retained after successful or cancelled terminal completion, released immediately after failure, and released at any terminal state when the TTL is 'active'. If a public API must reject payload mismatches or replay response bodies, keep that request ledger in the application boundary and trigger Runlane from the accepted request record.

Authoring And Validation

Public authoring APIs accept strings in place:

const emailQueue = queue({ name: 'emails', default: true })

const sendWelcomeEmail = task({
  id: 'emails.welcome',
  queue: emailQueue,
  schema,
  idempotencyKey: (payload) => `emails.welcome.${payload.userId}`,
  async run(payload) {
    await emailProvider.send(payload.userId)
  },
})

const runlane = createRunlane({
  lane,
  queues: [emailQueue],
  tasks: { sendWelcomeEmail },
})

await runlane.trigger(runlane.tasks.sendWelcomeEmail, { userId: 'user_123' })
await runlane.worker({ queues: [emailQueue] }).closed

Literal task IDs, static task keys, and task-colocated schedule IDs get TypeScript checks where possible. Queue names, explicit run IDs, worker IDs, and dynamic key resolver results still go through runtime validation because TypeScript cannot prove values from payloads, environment variables, HTTP requests, or databases are safe.

On this page