Skip to main content
context.run() executes a piece of custom business logic as a workflow step. It returns a Promise, so you can decide how steps execute:
  • Sequentially by awaiting them one by one.
  • In parallel by awaiting multiple steps together.

Arguments

stepName
string
A unique identifier for the step.
stepFunction
function
The business logic to run inside this step.

Response

Each step can return a JSON-serializable value—anything from simple primitives to complex objects. The value is JSON-serialized and automatically restored across requests.
Avoid returning stateful resources such as database connections or file handles.Instead, return plain data (numbers, strings, arrays, objects) so the result can be safely persisted and restored across workflow executions.

Usage

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

export const { POST } = serve<string>(async (context) => {
  const input = context.requestPayload;

  const result1 = await context.run("step-1", async () => {
    return someWork(input);
  });

  await context.run("step-2", async () => {
    someOtherWork(result1);
  });
});

Because results are JSON-serialized, class instances are restored as plain objects. This means instance methods will not be available unless you explicitly rehydrate the object.To fix this, you can recreate the instance using Object.assign() or a custom factory:
export const { POST } = serve(
async (context) => {

   let user = await context.run("step-1", async () => {
     // 👇 Return a class instance from step
     return new User("John Doe", "john.doe@example.com");
   });

   // 👇 Properties are accessible by default
   console.log(user.name)

   // 👇 Create a Proper Instance with Object.assign()
   user = Object.assign(new User(), user);

   await context.run("greet", async () => {
     // 👇 Now instance methods are available as well
     console.log(user.greet());
   });
 }
);