Overview

Upstash Workflow lets you write durable, reliable and performant serverless functions. Get delivery guarantees, automatic retries on failure, scheduling and more without managing any infrastructure.

  • No more function timeouts on serverless platforms
  • Automatic error recovery, continue a workflow run from any step
  • Integrates perfectly with your existing infrastructure; all code runs on your servers
  • Delivery guarantees, batching, schedules and more

Quickstarts

Workflow supports Next.js, Cloudflare Workers and many more frameworks.

How it works

Upstash Workflow builds on the principle of steps. Instead of defining a single, complex piece of business logic, workflows contain multiple individual steps.

In case of an error, a failed step is retried individually without needing to re-run any previous steps. Instead of the entire business logic, each step can take up your serverless function execution duration, and many more benefits.

Example workflow use-cases and their steps:

  • Image processing:

    1. Download an image
    2. Process the image
    3. Upload the processed image
  • SaaS Customer Onboarding

    1. Create user account
    2. Provision resources (e.g., storage, compute)
    3. Send welcome email
    4. Wait three days
    5. Send follow-up email
  • E-commerce order fulfillment:

    1. Validate order details
    2. Check inventory
    3. Process payment
    4. Generate shipping label
    5. Update inventory
    6. Send confirmation email

Next.js code example

Let’s see a practical implementation of Upstash Workflow using Next.js and customer onboarding as an example. See our Next.js Quickstart for a complete guide.

api/workflow/route.ts
import { serve } from "@upstash/qstash/nextjs";
import { sendEmail } from "./emailUtils";

// Type-safety for starting our workflow
interface InitialData {
  userId: string
  email: string
  name: string
}

export const POST = serve<InitialData>(async (context) => {
  const { userId, email, name } = context.requestPayload;

  // Step 1: Send welcome email
  await context.run("send-welcome-email", async () => {
    await sendEmail(email, "Welcome to our service!");
  });

  // Step 2: Wait for 3 days (in seconds)
  await context.sleep("sleep-until-follow-up", 60 * 60 * 24 * 3);

  // Step 3: AI-generate personalized follow-up message
  const aiResponse = await context.call(
    "generate-personalized-message",
    "https://api.openai.com/v1/chat/completions",
    "POST",
    {
      model: "gpt-3.5-turbo",
      messages: [
        { role: "system", content: "You are an assistant creating personalized follow-up messages." },
        { role: "user", content: `Create a short, friendly follow-up message for ${name} who joined our service 3 days ago.` }
      ]
    },
    { headers: { ... } }
  );

  const personalizedMessage = aiResponse.choices[0].message.content;

  // Step 4: Send personalized follow-up email
  await context.run("send-follow-up-email", async () => {
    await sendEmail(email, personalizedMessage);
  });
});

Any HTTP request using context.call, like the AI-generation above, does not count towards your function’s execution time and does not increase your serverless bill. It can also run for up to 2 hours, completely bypassing any platform-specific function timeouts.

The above example should give you a rough idea of how a workflow looks in code. For step-by-step instructions on setting up your first workflow with images along the way, see our Next.js Quickstart.


Here are more details about what the context object does:

See caveats for more complex API usage and best-practices when using Upstash Workflow.


Guides on common workflow topics:

If you’re curious about the behind-the-scenes about how we ensure separate step execution or prevent serverless timeouts, we wrote about it here! :)

Here is our Upstash Workflow roadmap to see what we planned for the future.