Skip to content

Nodes Overview

A node is a reusable, self-describing workflow building block. Every node on the canvas maps to a node definition that specifies:

  • What it does — a name, description, and category
  • What it needs — a config schema that drives the UI form automatically
  • What it produces — a typed output schema that downstream nodes can reference via {{nodeId.property}}
  • How it runs — one or more code templates, one per execution provider

Every node is automatically wrapped in step.do() by the compile pipeline. You never write retry or durability logic — the platform handles it.

Two Kinds of Nodes

Built-in Nodes

Built-in nodes are bundled with AwaitStep. They cannot be removed or overridden. There are 12 of them:

NodeCategoryDescription
stepControl FlowRun arbitrary TypeScript in a durable step
branchControl FlowConditional routing with multiple paths
parallelControl FlowRun multiple branches concurrently
loopControl FlowRepeat steps with forEach, while, or count
breakControl FlowExit a loop or stop workflow execution
raceControl FlowFirst branch to complete wins
try_catchControl FlowWrap steps in try/catch/finally
sleepSchedulingPause for a duration
sleep_untilSchedulingPause until a timestamp
wait_for_eventSchedulingPause until an external event arrives
http_requestHTTPMake an HTTP API call
sub_workflowControl FlowTrigger another workflow

See Built-in Nodes for the full reference.

Custom Nodes

Custom nodes extend AwaitStep with integrations you write or install from the marketplace. They follow the same NodeDefinition schema as built-in nodes and are indistinguishable from built-ins once installed.

There are two sources for custom nodes:

  • Local nodes — authored in your repository under nodes/<node_id>/
  • Remote nodes — installed from the AwaitStep marketplace or a custom registry

See Custom Nodes and Marketplace for details.

The NodeDefinition Model

Every node — built-in or custom — is described by a NodeDefinition object.

typescript
interface NodeDefinition {
  // Identity
  id: string // e.g. "stripe_charge"
  name: string // e.g. "Stripe Charge"
  version: string // Semver, e.g. "1.0.0"
  description: string // Max 120 chars
  category: Category
  tags?: string[]
  icon?: string // HTTPS URL to SVG icon
  docsUrl?: string
  author: string // GitHub username or org
  license: string // SPDX identifier

  // Schema
  configSchema: Record<string, ConfigField>
  outputSchema: Record<string, OutputField>

  // Providers
  providers: Provider[] // Which platforms have templates

  // Optional
  dependencies?: Record<string, string> // npm deps required at runtime
  runtime?: {
    defaultTimeout?: string
    defaultRetries?: number
    idempotent?: boolean
  }
  deprecated?: boolean
  deprecationMessage?: string
  replacedBy?: string
}

How Templates Work

Each node has one or more template files in its templates/ directory, named by provider (cloudflare.ts, inngest.ts, etc.). A template is a TypeScript module that exports a default async function:

typescript
import type { NodeContext } from '@awaitstep/node-sdk'

export default async function (ctx: NodeContext<Config>): Promise<Output> {
  // Business logic here
  // ctx.config — user-provided config values
  // ctx.env    — environment variables and secrets
  // ctx.inputs — outputs from upstream steps
  throw new Error('...') // Always throw on error — never swallow
}

At deploy time, the codegen pipeline resolves the correct template for the target provider and inlines the template body into a step.do() call in the generated worker.

NodeContext

typescript
interface NodeContext<TConfig = Record<string, unknown>> {
  config: TConfig // Config values from the drawer
  env: Record<string, string> // Env vars and secrets (ctx.env.MY_SECRET)
  inputs: Record<string, unknown> // Outputs from upstream steps
  workflow: {
    id: string // Workflow definition ID
    instanceId: string // This run's instance ID
    triggeredAt: string // ISO timestamp
  }
}

Template Rules

  • Use Web APIs only for Cloudflare templates (fetch, crypto, URL). No fs, path, process, or Buffer.
  • Never call step.do(), step.sleep(), or step.sleepUntil() inside a template — the platform wraps your code.
  • Always throw on errors. Never return { success: false }.
  • Access secrets via ctx.env.VAR_NAME, never via ctx.config.
  • Never log secret values.

Categories

CategoryExample nodes
Control Flowbranch, loop, parallel, try_catch
HTTPhttp_request
Schedulingsleep, wait_for_event
Paymentsstripe_charge, stripe_refund
Emailresend_send_email, sendgrid_send
Messagingslack_post_message, twilio_sms
Databasepostgres_query, d1_query
Storager2_put, s3_upload
AIopenai_chat, anthropic_message
Notificationspagerduty_alert
Datajson_transform, csv_parse
Utilitiesgenerate_uuid, format_date