Skip to content
Ironflow is pre-1.0: APIs can change between releases. Pin a version. What is ready →

Topics

Topics provide a general-purpose messaging layer on top of Ironflow’s NATS infrastructure. Use them for service-to-service communication, analytics, or notifications — without triggering workflows.

Featureemit()publish()
Namespaceevents:topic:
Triggers Functions?YesNo
Use CaseBusiness logic triggers.Real-time messages / broadcasting.

A topic name is at most 249 bytes. It cannot contain * or >, whitespace, control characters or an empty segment (a leading, trailing or doubled .). It cannot start with events:, system., entity:, public. or topic:, which Ironflow owns. A bad name fails with invalid_argument. See Reserved names.


import { createClient } from "@ironflow/node";
const ironflow = createClient({ apiKey: process.env.IRONFLOW_API_KEY });
await ironflow.publish("notifications.email", {
to: "user@example.com",
body: "Welcome to Ironflow!",
});

Use step.publish() to emit a message as a durable step. This ensures that if the workflow retries, the message is not published more than once.

import { ironflow } from "@ironflow/node";
export const myFn = ironflow.createFunction(config, async ({ step }) => {
// Durable publish — memoized and observable
await step.publish("analytics.workflow_step", { status: "reached" });
});
// Durable publish: memoized under the step name "publish:analytics.workflow_step"
if err := ironflow.Publish(ctx, "analytics.workflow_step", map[string]string{"status": "reached"}); err != nil {
return nil, err
}
from ironflow.worker import function
@function(id="my-fn", triggers=[{"event": "order.placed"}])
async def my_fn(ctx):
# Durable publish: memoized and observable
result = await ctx.step.publish("analytics.workflow_step", {"status": "reached"})
print(result.event_id, result.sequence)

Pass idempotency_key= to make the publish idempotent on the server too. The server remembers a key for one topic in one environment, for IRONFLOW_RUN_RETENTION_DAYS days after the first publish (kept forever when unset or 0). A repeat returns duplicate with the first event_id.

Under serve(), the function needs server_url= or IRONFLOW_SERVER_URL for step.publish. Without it, the run fails with “server URL not configured for publish step”. Pull-mode workers already have their URL.


Topics use the topic: prefix for subscriptions.

import { ironflow } from "@ironflow/browser";
await ironflow.subscribe("topic:notifications.>", {
onEvent: (event) => console.log("Broadcasting:", event.data),
});