All skills
upstash avatar

/upstash-workflow-js

@36daab8
by upstashupstash/skills27 stars
7

Work with the @upstash/workflow TypeScript/JavaScript SDK for durable, long-running workflows in serverless functions, multi-step processes that survive timeouts, retries, and restarts (built on QStash). Use when defining a workflow endpoint with serve(), running steps with context.run, sleeping for minutes to days without holding a function open, calling external APIs with context.call, waiting for an external event or webhook, invoking other workflows, configuring retries, failure callbacks, and a DLQ, controlling concurrency, rate, and parallelism, triggering, cancelling, or inspecting runs with the Workflow client, building AI agents and orchestrators, human-in-the-loop approvals, realtime updates, local development with the QStash dev server, adding middleware, or migrating workflows safely. Also use when the user asks for durable execution, step functions, saga or orchestration patterns, background jobs with checkpoints, or long-running tasks on Vercel, Next.js, Cloudflare Workers, or other serverless platforms.

Use this Skill: https://skilld.dev/gh/upstash/skills/upstash-workflow-js

This session only. Nothing lands on disk.

how-tomiddleware.md

≈1.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Middlewares

This guide explains how to intercept workflow lifecycle and debug events using middleware. It covers how to attach middlewares, define event handlers, initialize resources, and combine functionality into efficient implementations.

Overview

Middlewares plug into the workflow engine and listen to:

  • Lifecycle events such as run start, run completion, and step execution
  • Debug messages such as errors, warnings, and informational logs

They are useful for logging, monitoring, instrumentation, and integrating with external systems.

Using Built‑in Middleware

Add middleware inside the middlewares array when serving a workflow:

import { serve } from "@upstash/workflow/nextjs";
import { loggingMiddleware } from "@upstash/workflow";

export const { POST } = serve(
  async (ctx) => {
    await ctx.run("step-1", () => "Hello World");
  },
  {
    middlewares: [loggingMiddleware], // emits run/step logs
  }
);

Creating Custom Middleware

You define middleware by instantiating WorkflowMiddleware with callbacks for the events you want to handle.

Direct Callback Definitions

All lifecycle and debug events can be defined in one object.

import { WorkflowMiddleware } from "@upstash/workflow";

const customMiddleware = new WorkflowMiddleware({
  name: "custom-logger",
  callbacks: {
    // Lifecycle events
    runStarted: async ({ context }) => {
      console.log(`Run ${context.workflowRunId} started`);
    },
    beforeExecution: async ({ context, stepName }) => {
      console.log(`→ Executing step: ${stepName}`);
    },
    afterExecution: async ({ context, stepName, result }) => {
      console.log(`✓ Step ${stepName} completed`, result);
    },
    runCompleted: async ({ context, result }) => {
      console.log(`Run ${context.workflowRunId} finished`, result);
    },

    // Debug events
    onError: async ({ workflowRunId, error }) => {
      console.error(`Error in ${workflowRunId}`, error);
    },
    onWarning: async ({ workflowRunId, warning }) => {
      console.warn(`Warning from ${workflowRunId}`, warning);
    },
    onInfo: async ({ workflowRunId, info }) => {
      console.info(`Info from ${workflowRunId}`, info);
    },
  },
});

Initialization With init

Use init when you need setup logic (connecting to a DB, creating clients, loading configuration). init returns an object containing the callbacks.

import { WorkflowMiddleware } from "@upstash/workflow";

const databaseMiddleware = new WorkflowMiddleware({
  name: "database-logger",
  init: async () => {
    const db = await connectToDatabase();

    return {
      runStarted: async ({ context }) => {
        await db.insert({ workflowRunId: context.workflowRunId, status: "started" });
      },
      runCompleted: async ({ context, result }) => {
        await db.update({ workflowRunId: context.workflowRunId, status: "completed", result });
      },
      onError: async ({ workflowRunId, error }) => {
        await db.insert({ workflowRunId, level: "error", message: error.message });
      },
    };
  },
});

Event Reference

Below is a concise list of supported event handlers and what they receive.

Lifecycle

  • runStarted: { context }
  • beforeExecution: { context, stepName }
  • afterExecution: { context, stepName, result }
  • runCompleted: { context, result }

Debug

  • onError: { workflowRunId?, error }
  • onWarning: { workflowRunId?, warning }
  • onInfo: { workflowRunId?, info }

Combined Example

Single snippet showing typical usage patterns.

import { serve } from "@upstash/workflow/nextjs";
import { WorkflowMiddleware } from "@upstash/workflow";

// Error tracking
const errorTrackingMiddleware = new WorkflowMiddleware({
  name: "errors",
  callbacks: {
    onError: async ({ workflowRunId, error }) => {
      await fetch("https://monitoring/errors", {
        method: "POST",
        body: JSON.stringify({ workflowRunId, error: error.message }),
      });
    },
  },
});

// Performance measurement
const timings = new Map();
const performanceMiddleware = new WorkflowMiddleware({
  name: "perf",
  callbacks: {
    beforeExecution: ({ stepName }) => timings.set(stepName, Date.now()),
    afterExecution: ({ stepName }) => {
      const t = timings.get(stepName);
      if (t) console.log(`Step ${stepName} took ${Date.now() - t}ms`);
      timings.delete(stepName);
    },
  },
});

export const { POST } = serve(
  async (ctx) => {
    await ctx.run("task", () => "done");
  },
  {
    middlewares: [errorTrackingMiddleware, performanceMiddleware],
  }
);

Pitfalls and Tips

  • Ensure init returns all callbacks; missing keys simply mean the event is ignored.
  • Debug events may be called without a workflowRunId if errors occur before run id is identified.

Source: SKILL.md on GitHub

1 warning17d3 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    The skill is a comprehensive documentation and implementation guide for the Upstash Workflow SDK. It covers durable serverless workflows, agent orchestration, and reliability features. All identified external resources and tool downloads are official components of the Upstash platform or well-known development services. No security issues or malicious patterns were detected.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: MEDIUM · 1 issue

Signed by skilld at 36daab8. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 6 days ago.

Activeupdated last month
metadata
{
  "author": "Upstash",
  "homepage": "https://upstash.com"
}

README badge

README badge for upstash/skills/upstash-workflow-js