Source Code

This is a step by step guide on how to receive webhooks from qstash in your Next.js app.


Create a new nextjs app named `qstash-receiver`

There are great tutorials on how to setup Next.js on Vercel, so I won’t go into details here.

npx create-next-app qstash-receiver
cd qstash-receiver

Install qstash

npm install @upstash/qstash@latest

Write your function

  • Serverless Function

  • App Route

  • Edge Function

import type { NextApiRequest, NextApiResponse } from "next";
import { verifySignature } from "@upstash/qstash/dist/nextjs";

async function handler(req: NextApiRequest, res: NextApiResponse) {

  await new Promise((r) => setTimeout(r, 1000));

  console.log(typeof req.body, { body: req.body });
  res.status(200).json({ name: "John Doe", body: req.body });

export default verifySignature(handler);

export const config = {
  api: {
    bodyParser: false,

verifySignature or verifySignatureEdge will try to load QSTASH_CURRENT_SIGNING_KEY and QSTASH_NEXT_SIGNING_KEY from the environment. If one of them is missing, an error is thrown. We will set these in step 5.


Deploy to Vercel

I’m deploying using Vercel’s CLI, but you could also push your project to a remote repo and deploy that way. If you have never used the cli, please run npx vercel login before. See here

You can accept all the default settings.

$ npx vercel

Vercel CLI 24.2.5
? Set up and deploy “~/github/upstash/qstash-examples/vercel-nextjs”? [Y/n] y
? Which scope do you want to deploy to? Andreas Thomas
? Link to existing project? [y/N] n
? What’s your project’s name? vercel-nextjs
? In which directory is your code located? ./
Auto-detected Project Settings (Next.js):
- Build Command: next build
- Output Directory: Next.js default
- Development Command: next dev --port $PORT
? Want to override the settings? [y/N] n
🔗  Linked to chronark/vercel-nextjs (created .vercel)
🔍  Inspect: [904ms]
✅  Production: [copied to clipboard] [37s]
📝  Deployed to production. Run `vercel --prod` to overwrite later (
💡  To change the domain or build command, go to

Set Signing Keys in Vercel

Go to your project’s settings and set the following environment variables:


Redeploy to use the new environment variables

To make the added environment variables take effect, you must redeploy your project.

$ npx vercel --prod
Vercel CLI 24.2.5
🔍  Inspect: [3s]
✅  Production: [copied to clipboard] [39s]

Publish a message

Go to your project’s logs and then publish a new message.

curl --request POST "" \
     -H "Authorization: Bearer <QSTASH_TOKEN>" \
     -H "Content-Type: application/json" \
     -d "{ \"hello\": \"world\"}"

In the logs you should see something like this:

[POST] /api/qstash
If this is printed, the signature has already been verified

That’s it, you have successfully created a secure Next.js API route, that receives and verifies incoming webhooks from qstash.

Learn more about publishing a message to qstash here