Skip to content

Latest commit

 

History

History
438 lines (314 loc) · 13.3 KB

File metadata and controls

438 lines (314 loc) · 13.3 KB
title Next.js setup guide
sidebarTitle Next.js
description This guide will show you how to setup Trigger.dev in your existing Next.js project, test an example task, and view the run.
icon N

import Prerequisites from "/snippets/framework-prerequisites.mdx"; import CliInitStep from "/snippets/step-cli-init.mdx"; import CliDevStep from "/snippets/step-cli-dev.mdx"; import CliRunTestStep from "/snippets/step-run-test.mdx"; import CliViewRunStep from "/snippets/step-view-run.mdx"; import UsefulNextSteps from "/snippets/useful-next-steps.mdx"; import TriggerTaskNextjs from "/snippets/trigger-tasks-nextjs.mdx"; import NextjsTroubleshootingMissingApiKey from "/snippets/nextjs-missing-api-key.mdx"; import NextjsTroubleshootingButtonSyntax from "/snippets/nextjs-button-syntax.mdx"; import WorkerFailedToStartWhenRunningDevCommand from "/snippets/worker-failed-to-start.mdx"; import AddEnvironmentVariables from "/snippets/add-environment-variables.mdx"; import DeployingYourTask from "/snippets/deplopying-your-task.mdx"; import VercelDocsCards from "/snippets/vercel-docs-cards.mdx";

import RunDevAndNextConcurrently from "/snippets/run-dev-and-next-concurrently.mdx";

This guide can be followed for both App and Pages router as well as Server Actions.

Initial setup

Set your secret key locally

Set your TRIGGER_SECRET_KEY environment variable in your .env.local file if using the Next.js App router or .env file if using Pages router. This key is used to authenticate with Trigger.dev, so you can trigger runs from your Next.js app. Visit the API Keys page in the dashboard and select the DEV secret key.

How to find your secret key

For more information on authenticating with Trigger.dev, see the API keys page.

Triggering your task in Next.js

Here are the steps to trigger your task in the Next.js App and Pages router and Server Actions. Alternatively, check out this repo for a full working example of a Next.js app with a Trigger.dev task triggered using a Server Action.

  Add a Route Handler by creating a `route.ts` file (or `route.js` file) in the `app/api` directory like this: `app/api/hello-world/route.ts`.
  Add this code to your `route.ts` file which imports your task along with `NextResponse` to handle the API route response:

  ```ts app/api/hello-world/route.ts
  // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
  import type { helloWorldTask } from "@/trigger/example";
  import { tasks } from "@trigger.dev/sdk/v3";
  import { NextResponse } from "next/server";

  //tasks.trigger also works with the edge runtime
  //export const runtime = "edge";

  export async function GET() {
    const handle = await tasks.trigger<typeof helloWorldTask>(
      "hello-world",
      "James"
    );

    return NextResponse.json(handle);
  }
  ```

</Step>

<Step title="Trigger your task">

<TriggerTaskNextjs/>

</Step>

</Steps>

</Tab>

<Tab title="App Router (Server Actions)">

<Steps>

<Step title="Create an `actions.ts` file">

  Create an `actions.ts` file in the `app/api` directory and add this code which imports your `helloWorldTask()` task. Make sure to include `"use server";` at the top of the file.

  ```ts app/api/actions.ts
    "use server";

    import type { helloWorldTask } from "@/trigger/example";
    import { tasks } from "@trigger.dev/sdk/v3";

    export async function myTask() {
      try {
        const handle = await tasks.trigger<typeof helloWorldTask>(
          "hello-world",
          "James"
        );

        return { handle };
      } catch (error) {
        console.error(error);
        return {
          error: "something went wrong",
        };
      }
    }
  ```

</Step>

<Step title="Create a button to trigger your task">

  For the purposes of this guide, we'll create a button with an `onClick` event that triggers your task. We'll add this to the `page.tsx` file so we can trigger the task by clicking the button. Make sure to import your task and include `"use client";` at the top of your file.

  ```ts app/page.tsx
  "use client";

  import { myTask } from "./actions";

  export default function Home() {
    return (
      <main className="flex min-h-screen flex-col items-center justify-center p-24">
        <button
          onClick={async () => {
            await myTask();
          }}
        >
          Trigger my task
        </button>
      </main>
    );
  }
  ```
</Step>

<Step title="Trigger your task">

Run your Next.js app:

<CodeGroup>

```bash npm
npm run dev
```

```bash pnpm
pnpm run dev
```

```bash yarn
yarn dev
```

</CodeGroup>

Open your app in a browser, making sure the port number is the same as the one you're running your Next.js app on. For example, if you're running your Next.js app on port 3000, visit:

```bash
http://localhost:3000
```

Run the dev server from Step 2. of the [Initial Setup](/guides/frameworks/nextjs#initial-setup) section above if it's not already running:

<CodeGroup>

```bash npm
npx trigger.dev@latest dev
```

```bash pnpm
pnpm dlx trigger.dev@latest dev
```

```bash yarn
yarn dlx trigger.dev@latest dev
```

</CodeGroup>

Then click the button we created in your app to trigger the task. You should see the CLI log the task run with a link to view the logs.

![Trigger.dev CLI showing a successful run](/images/trigger-cli-run-success.png)

Visit the [Trigger.dev dashboard](https://cloud.trigger.dev) to see your run.

</Step>

</Steps>

</Tab>

<Tab title="Pages Router">

<Steps>

<Step title="Create an API route">

  Create an API route in the `pages/api` directory. Then create a `hello-world .ts` (or `hello-world.js`) file for your task and copy this code example:

  ```ts pages/api/hello-world.ts
  // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
  import { helloWorldTask } from "@/trigger/example";
  import { tasks } from "@trigger.dev/sdk/v3";
  import type { NextApiRequest, NextApiResponse } from "next";

  export default async function handler(
    req: NextApiRequest,
    res: NextApiResponse<{ id: string }>
  ) {
    const handle = await tasks.trigger<typeof helloWorldTask>(
    "hello-world",
    "James"
    );

    res.status(200).json(handle);
  }
  ```
</Step>

<Step title="Trigger your task">

<TriggerTaskNextjs/>

</Step>

</Steps>

</Tab>

Automatically sync environment variables from your Vercel project (optional)

If you want to automatically sync environment variables from your Vercel project to Trigger.dev, you can add our syncVercelEnvVars build extension to your trigger.config.ts file.

You need to set the `VERCEL_ACCESS_TOKEN` and `VERCEL_PROJECT_ID` environment variables, or pass in the token and project ID as arguments to the `syncVercelEnvVars` build extension. If you're working with a team project, you'll also need to set `VERCEL_TEAM_ID`, which can be found in your team settings. You can find / generate the `VERCEL_ACCESS_TOKEN` in your Vercel [dashboard](https://vercel.com/account/settings/tokens). Make sure the scope of the token covers the project with the environment variables you want to sync.
import { defineConfig } from "@trigger.dev/sdk/v3";
import { syncVercelEnvVars } from "@trigger.dev/build/extensions/core";

export default defineConfig({
  project: "<project ref>",
  // Your other config settings...
  build: {
    extensions: [syncVercelEnvVars()],
  },
});
For more information, see our [Vercel sync environment variables](/guides/examples/vercel-sync-env-vars) guide.

Troubleshooting & extra resources

Revalidation from your Trigger.dev tasks

Revalidation allows you to purge the cache for an ISR route. To revalidate an ISR route from a Trigger.dev task, you have to set up a handler for the revalidate event. This is an API route that you can add to your Next.js app.

This handler will run the revalidatePath function from Next.js, which purges the cache for the given path.

The handlers are slightly different for the App and Pages router:

Revalidation handler: App Router

If you are using the App router, create a new revalidation route at app/api/revalidate/path/route.ts:

import { NextRequest, NextResponse } from "next/server";
import { revalidatePath } from "next/cache";

export async function POST(request: NextRequest) {
  try {
    const { path, type, secret } = await request.json();
    // Create a REVALIDATION_SECRET and set it in your environment variables
    if (secret !== process.env.REVALIDATION_SECRET) {
      return NextResponse.json({ message: "Invalid secret" }, { status: 401 });
    }

    if (!path) {
      return NextResponse.json({ message: "Path is required" }, { status: 400 });
    }

    revalidatePath(path, type);

    return NextResponse.json({ revalidated: true });
  } catch (err) {
    console.error("Error revalidating path:", err);
    return NextResponse.json({ message: "Error revalidating path" }, { status: 500 });
  }
}

Revalidation handler: Pages Router

If you are using the Pages router, create a new revalidation route at pages/api/revalidate/path.ts:

import type { NextApiRequest, NextApiResponse } from "next";

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  try {
    if (req.method !== "POST") {
      return res.status(405).json({ message: "Method not allowed" });
    }

    const { path, secret } = req.body;

    if (secret !== process.env.REVALIDATION_SECRET) {
      return res.status(401).json({ message: "Invalid secret" });
    }

    if (!path) {
      return res.status(400).json({ message: "Path is required" });
    }

    await res.revalidate(path);

    return res.json({ revalidated: true });
  } catch (err) {
    console.error("Error revalidating path:", err);
    return res.status(500).json({ message: "Error revalidating path" });
  }
}

Revalidation task

This task takes a path as a payload and will revalidate the path you specify, using the handler you set up previously.

To run this task locally you will need to set the REVALIDATION_SECRET environment variable in your .env.local file (or .env file if using Pages router).

To run this task in production, you will need to set the REVALIDATION_SECRET environment variable in Vercel, in your project settings, and also in your environment variables in the Trigger.dev dashboard.

import { logger, task } from "@trigger.dev/sdk/v3";

const NEXTJS_APP_URL = process.env.NEXTJS_APP_URL; // e.g. "http://localhost:3000" or "https://my-nextjs-app.vercel.app"
const REVALIDATION_SECRET = process.env.REVALIDATION_SECRET; // Create a REVALIDATION_SECRET and set it in your environment variables

export const revalidatePath = task({
  id: "revalidate-path",
  run: async (payload: { path: string }) => {
    const { path } = payload;

    try {
      const response = await fetch(`${NEXTJS_APP_URL}/api/revalidate/path`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          path: `${NEXTJS_APP_URL}/${path}`,
          secret: REVALIDATION_SECRET,
        }),
      });

      if (response.ok) {
        logger.log("Path revalidation successful", { path });
        return { success: true };
      } else {
        logger.error("Path revalidation failed", {
          path,
          statusCode: response.status,
          statusText: response.statusText,
        });
        return {
          success: false,
          error: `Revalidation failed with status ${response.status}: ${response.statusText}`,
        };
      }
    } catch (error) {
      logger.error("Path revalidation encountered an error", {
        path,
        error: error instanceof Error ? error.message : String(error),
      });
      return {
        success: false,
        error: `Failed to revalidate path due to an unexpected error`,
      };
    }
  },
});

Testing the revalidation task

You can test your revalidation task in the Trigger.dev dashboard on the testing page, using the following payload.

{
  "path": "<path-to-revalidate>" // e.g. "blog"
}
<NextjsTroubleshootingMissingApiKey/>
<NextjsTroubleshootingButtonSyntax/>
<WorkerFailedToStartWhenRunningDevCommand/>