> ## Documentation Index
> Fetch the complete documentation index at: https://upstash-vector.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Next.js on Vercel

[Source Code](https://github.com/upstash/qstash-examples/tree/main/vercel-nextjs)

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

<Steps>
  <Step titleSize="h3" title="Create a new nextjs app named `qstash-receiver`">
    There are [great tutorials](https://nextjs.org/learn/basics/create-nextjs-app/setup) on
    how to setup Next.js on [Vercel](https://vercel.com/), so I won't go into
    details here.

    ```bash
    npx create-next-app qstash-receiver
    cd qstash-receiver
    ```
  </Step>

  <Step titleSize="h3" title="Install qstash">
    ```bash
    npm install @upstash/qstash@latest
    ```
  </Step>

  <Step titleSize="h3" title="Write your function">
    <Tabs>
      <Tab title="Pages Serverless Function">
        ```ts /pages/api/qstash-serverless.ts
        import type { NextApiRequest, NextApiResponse } from "next";
        import { verifySignature } from "@upstash/qstash/dist/nextjs";

        async function handler(req: NextApiRequest, res: NextApiResponse) {
          console.log(req.headers);

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

          console.log("Success");
          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,
          },
        };
        ```
      </Tab>

      <Tab title="Pages Edge">
        ```ts /pages/api/qstash-edge.ts
        import { NextRequest, NextResponse } from "next/server";
        import { verifySignatureEdge } from "@upstash/qstash/dist/nextjs";

        async function handler(req: NextRequest) {
            console.log(req.headers);
            await new Promise((r) => setTimeout(r, 1000));
            console.log("Success");
            console.log(typeof req.body, { body: req.body });
            return NextResponse.json({ name: "John Doe", body: req.body });
        }

        export default verifySignatureEdge(handler);
        export const config = {
            runtime: "edge",
            api: {
            bodyParser: false,
            },
        };
        ```
      </Tab>

      <Tab title="App Router Serverless">
        ```ts /app/api/qstash-serverless/route.ts
        import { NextRequest, NextResponse } from "next/server";
        import { verifySignatureAppRouter } from "@upstash/qstash/dist/nextjs";

        async function handler(_req: NextRequest) {
          await new Promise((r) => setTimeout(r, 1000));

          console.log("Success");
          return NextResponse.json({ name: "John Doe " });
        }

        export const POST = verifySignatureAppRouter(handler);
        ```
      </Tab>

      <Tab title="App Router Edge">
        ```ts /app/api/qstash-edge/route.ts
        import { NextRequest, NextResponse } from "next/server";
        import { verifySignatureEdge } from "@upstash/qstash/dist/nextjs";

        async function handler(_req: NextRequest) {
          await new Promise((r) => setTimeout(r, 1000));

          console.log("Success");
          return NextResponse.json({ name: "John Doe" });
        }

        export const POST = verifySignatureEdge(handler);
        export const runtime = "edge";
        ```
      </Tab>
    </Tabs>

    `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.
  </Step>

  <Step titleSize="h3" title="Deploy to Vercel">
    I'm deploying using [Vercel's CLI](https://vercel.com/docs/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](https://vercel.com/docs/cli#commands/login)

    You can accept all the default settings.

    ```bash
    $ 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: https://vercel.com/chronark/vercel-nextjs/FZScmeKCWr5snn6P8voyv3W28npf [904ms]
    ✅  Production: https://vercel-nextjs-two-sandy.vercel.app [copied to clipboard] [37s]
    📝  Deployed to production. Run `vercel --prod` to overwrite later (https://vercel.link/2F).
    💡  To change the domain or build command, go to https://vercel.com/chronark/vercel-nextjs/settings
    ```
  </Step>

  <Step titleSize="h3" title="Set Signing Keys in Vercel">
    Go to your project's settings and set the following environment variables:

    ![](https://mintlify.s3-us-west-1.amazonaws.com/upstash-vector/img/qstash/vercel_env.png)
  </Step>

  <Step titleSize="h3" title="Redeploy to use the new environment variables">
    To make the added environment variables take effect, you must redeploy your
    project.

    ```bash
    $ npx vercel --prod
    Vercel CLI 24.2.5
    🔍  Inspect: https://vercel.com/chronark/vercel-nextjs/3wPxyEPwdcMrncSNqFNcDD41rjxB [3s]
    ✅  Production: https://vercel-nextjs-two-sandy.vercel.app [copied to clipboard] [39s]
    ```
  </Step>

  <Step titleSize="h3" title="Publish a message">
    Go to your project's logs and then publish a new message.

    ```bash
    curl --request POST "https://qstash.upstash.io/v2/publish/https://vercel-nextjs-two-sandy.vercel.app/api/qstash" \
         -H "Authorization: Bearer <QSTASH_TOKEN>" \
         -H "Content-Type: application/json" \
         -d "{ \"hello\": \"world\"}"
    ```

    ```bash
    {"messageId":"msg_5GJrFa5aMFxDYsDygAnW9YW8cmRm"}
    ```

    In the logs you should see something like this:

    ```
    [POST] /api/qstash
    If this is printed, the signature has already been verified
    ```
  </Step>
</Steps>

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](/qstash/howto/publishing)
