Aiki
Guides

Reference IDs

Address workflows, events and schedules by your own identifiers, and prevent duplicates.

Reference IDs let you assign custom identifiers to workflows, events, and schedules. This enables tracking, correlation with your systems, and lookup by your own IDs. As a secondary benefit, reference IDs prevent duplicate executions when the same reference is reused.

What are Reference IDs?

A reference ID is a custom identifier you provide when starting a workflow, sending an event, or activating a schedule. Use cases include:

  • Tracking: Correlate Aiki workflows with your order IDs, user IDs, or transaction IDs
  • Lookup: Find a workflow run using your own identifier instead of Aiki's internal run ID
  • Duplicate prevention: When a reference ID is reused, Aiki can either throw an error, return the existing run, or silently deduplicate (for events)

Reference IDs are unique per workflow version (workflow name + version ID). The same reference ID can be used across different workflow versions without conflict.

Note: Tasks do not support reference IDs. Tasks are content-addressed by name + hash(input) — see Content-Addressed Memoization for how this works.

Workflow Reference IDs

When starting workflows, you can provide a reference ID:

// Start a workflow with a reference ID
const handle = await orderWorkflowV1
  .with("reference.id", "order-123")
  .start(client, { orderId: "order-123", items: [...] });

// You can now look up this workflow using "order-123"
// If you try to start another workflow with the same reference ID,
// Aiki will throw an error by default (configurable via conflictPolicy)

Conflict Handling

By default, Aiki throws an error when you try to start a workflow with a reference ID that already exists but with different input. You can configure this behavior with the conflictPolicy option:

// Default behavior: throw error on conflict
const handle = await orderWorkflowV1
  .with("reference", { id: "order-123-process", conflictPolicy: "error" })
  .start(client, { orderId: "order-123", items: [...] });

// Alternative: return existing run on conflict
const handle = await orderWorkflowV1
  .with("reference", { id: "order-123-process", conflictPolicy: "return_existing" })
  .start(client, { orderId: "order-123", items: [...] });

// With "return_existing", duplicate calls return the same workflow run
// handle.id will be the same as the original run

Event Reference IDs

When sending events to a workflow, you can provide a reference ID to prevent duplicate event delivery:

// Send an event with a reference ID
await handle.events.approved
  .with("reference.id", "approval-123")
  .send({ by: "manager@example.com" });

// If the same event is sent again with the same reference ID,
// it will be silently ignored (no error, no duplicate)
await handle.events.approved
  .with("reference.id", "approval-123")
  .send({ by: "manager@example.com" }); // Ignored - duplicate

// Without options, use send directly
await handle.events.approved.send({ by: "manager@example.com" });

Unlike workflows, events use silent deduplication - duplicate events are simply ignored rather than throwing an error.

Schedule Reference IDs

When activating schedules, you can provide a reference ID for explicit identity:

const handle = await dailyReport
	.with("reference", {
		id: "tenant-acme-daily-report",
		conflictPolicy: "error",
	})
	.activate(client, reportWorkflowV1, { tenantId: "acme" });

Schedules use the same conflict policies as workflows:

PolicyBehavior
"error" (default)Throw a ScheduleConflictError if the reference ID already identifies a schedule with a different definition
"return_existing"Return the existing schedule unchanged

A schedule's definition is immutable, so a reference ID that already points at a different definition is a conflict, never an update. "error" throws a ScheduleConflictError; "return_existing" hands back the existing schedule as-is.

See the Schedules documentation for more details.

How It Works

Workflow Level

When you provide a reference ID when starting a workflow, the system checks if a workflow run with that ID already exists. Based on the conflictPolicy setting:

  • "error" (default): Throws an error if a run exists with different input
  • "return_existing": Returns the existing workflow run

Benefits of Reference IDs

Reference IDs provide several benefits:

  • External correlation: Track workflows using your own identifiers (order IDs, user IDs, etc.)
  • Lookup capability: Find workflow runs by reference ID instead of internal run IDs
  • Duplicate prevention: Prevent accidental duplicate workflow or event executions when retrying requests

On this page