Skip to main content
Upstash Workflow is built on top of Upstash QStash. The QStash CLI provides a local development server that performs QStash functionality locally for development and testing purposes.
1

Install and Start Development Server

Start the development server using the QStash CLI:
npx @upstash/qstash-cli dev
The QStash CLI output will look something like this:
QStash CLI Output
Upstash QStash development server is runnning at

A default user has been created for you to authorize your requests.
QSTASH_TOKEN=eyJVc2VySUQiOiJkZWZhdWx0VXNlciIsIlBhc3N3b3JkIjoiZGVmYXVsdFBhc3N3b3JkIn0=
QSTASH_CURRENT_SIGNING_KEY=sig_7RvLjqfZBvP5KEUimQCE1pvpLuou
QSTASH_NEXT_SIGNING_KEY=sig_7W3ZNbfKWk5NWwEs3U4ixuQ7fxwE

Sample cURL request:
curl -X POST http://127.0.0.1:8080/v2/publish/https://example.com -H "Authorization: Bearer eyJVc2VySUQiOiJkZWZhdWx0VXNlciIsIlBhc3N3b3JkIjoiZGVmYXVsdFBhc3N3b3JkIn0="

Check out documentation for more details:
https://upstash.com/docs/qstash/howto/local-development
For detailed instructions on setting up the development server, see our QStash Local Development Guide.
2

Enable Local Mode on Console

Once you start the local server, you can go to the Workflow tab on Upstash Console and enable local mode, which will allow you to monitor and debug workflow runs with the local server.
3

Update Environment Variables

Once your development server is running, update your environment variables to route QStash requests to your local server.
QSTASH_URL="http://127.0.0.1:8080"
QSTASH_TOKEN="eyJVc2VySUQiOiJkZWZhdWx0VXNlciIsIlBhc3N3b3JkIjoiZGVmYXVsdFBhc3N3b3JkIn0="
QSTASH_CURRENT_SIGNING_KEY="sig_7RvLjqfZBvP5KEUimQCE1pvpLuou"
QSTASH_NEXT_SIGNING_KEY="sig_7W3ZNbfKWk5NWwEs3U4ixuQ7fxwE"
4

Use local addresses

It’s all set up 🎉Now, you can use your local address when triggering the workflow runs.
import { Client } from "@upstash/workflow";

const client = Client()

const { workflowRunId } = await client.trigger({
    url: `http://localhost:3000/api/workflow`,
    retries: 3,
});
Inside the trigger() call, you need to provide the URL of your workflow endpoint:To avoid hardcoding URLs, you can define a BASE_URL constant and set it based on the environment. A common pattern is to check an environment variable that only exists in production:
const BASE_URL = process.env.VERCEL_URL
  ? `https://${process.env.VERCEL_URL}`
  : `http://localhost:3000`

const { workflowRunId } = await client.trigger({
    url: `${BASE_URL}/api/workflow`,
    retries: 3,
});