Welcome to Chapter 2! In the previous chapter, we explored the “why” behind Trigger.dev, understanding its role in building robust, fault-tolerant AI agents and automated workflows. Now, it’s time to roll up our sleeves and dive into the “how.”

This chapter will guide you through setting up your local development environment for Trigger.dev v4-beta and creating your very first job. By the end, you’ll have a running Trigger.dev project, a basic understanding of its core components, and the satisfaction of seeing your first durable workflow execute. This hands-on experience is crucial for building confidence and understanding how Trigger.dev fits into your development stack.

Preparing Your Development Environment

Before we jump into Trigger.dev, let’s ensure your local machine has the necessary tools. Think of this as preparing your workshop before starting a new project.

Prerequisites: Node.js and npm

Trigger.dev projects typically run on Node.js and leverage npm (Node Package Manager) or Yarn for dependency management.

  1. Node.js (LTS Version): Trigger.dev requires Node.js version 18 or higher. The current Long Term Support (LTS) release is always recommended for stability and ongoing support.

    • Why it matters: Newer Node.js versions bring performance improvements, security fixes, and modern JavaScript features that Trigger.dev utilizes. Using an older version might lead to compatibility issues or missing features.
    • Check your version: Open your terminal or command prompt and run:
      node -v
      
    • If your version is older than 18, you’ll need to upgrade. We recommend using a Node Version Manager like nvm for easy switching between Node.js versions.
  2. npm (or Yarn): npm is usually installed automatically when you install Node.js.

    • Check your version:
      npm -v
      
    • If you prefer Yarn, ensure it’s installed globally:
      yarn -v
      
    • ⚡ Quick Note: While npm is the default, Trigger.dev supports yarn as well. The initialization process will adapt to your preference if you have Yarn installed.

Core Concepts: Building Blocks of a Trigger.dev Workflow

Before we write any code, let’s establish a mental model for what we’re about to build. Understanding these core concepts will make the implementation steps much clearer.

What is a Trigger.dev Job?

At its heart, a Trigger.dev job is a durable, fault-tolerant function that executes in response to an event.

  • What it is: A unit of work defined in your code that Trigger.dev manages. Think of it as a specific task, like “send a welcome email” or “process a payment.”
  • Why it exists: To perform tasks reliably, even if your server crashes, the network goes down, or an external API is temporarily unavailable. Trigger.dev ensures the job either completes successfully or is retried until it does, providing robust operations in unpredictable environments.
  • How it works: You define a job, specifying what event triggers it and what code it should run. Trigger.dev then orchestrates its execution, including retries, delays, and state management, ensuring its eventual completion.

Triggers and Events

Every Trigger.dev job starts with a trigger. This is how your job knows when to spring into action.

  • Trigger: The condition that causes a job to start. This could be a scheduled interval (e.g., “every hour”), an incoming HTTP webhook event (e.g., “when a user signs up”), or a custom event you send programmatically.
  • Event: The actual data payload that initiates a job. When a trigger fires, it often carries an event with relevant data for the job to process. For example, a user.signed.up event might carry the user’s ID and email address, which the job then uses to personalize a welcome message.

The Trigger.dev CLI

The Trigger.dev Command Line Interface (CLI) is your primary tool for initializing projects and interacting with the Trigger.dev platform.

  • What it is: A command-line utility that helps you set up and manage your Trigger.dev projects.
  • Why it exists: To streamline the initial setup, ensuring you have the correct project structure and dependencies, and to connect your local development environment to the Trigger.dev cloud service. It automates much of the boilerplate.
  • How it works: We’ll use npx trigger.dev@v4-beta init to scaffold a new project, which handles installing the necessary SDKs and creating boilerplate configuration files. This command allows you to use the CLI without a global installation.

Step-by-Step Implementation: Your First Workflow

Let’s get hands-on and create a simple “Hello World” job. This will demonstrate the full lifecycle from setup to execution.

Step 1: Create Your Project Directory

First, create a new directory for your Trigger.dev project and navigate into it. This keeps your project organized and separate from other codebases.

mkdir my-first-trigger-project
cd my-first-trigger-project

Step 2: Initialize Trigger.dev v4-beta

Now, we’ll use the Trigger.dev CLI to set up our project. We’ll specifically target the v4-beta version, as it’s the latest cutting-edge release, with General Availability (GA) expected around May/June 2026. This ensures you’re working with the most modern features.

npx trigger.dev@v4-beta init
  • What’s happening here?
    • npx: This command executes a Node.js package without requiring you to globally install it first. It’s great for one-off commands or trying out new tools.
    • trigger.dev@v4-beta: Specifies the Trigger.dev package and explicitly requests its v4-beta version.
    • init: This is the command to initialize a new Trigger.dev project, setting up all the necessary files and configurations.
  • Interactive Setup: The CLI will ask you a few questions to configure your project:
    • What framework are you using?: For this example, choose Next.js. Even if you’re not building a full Next.js application, it provides a well-structured starting point for a Node.js project that integrates well with Trigger.dev.
    • What is your project's root directory?: Press Enter to accept the default (.), meaning the current directory will be your project root.
    • What is your API Key?: You’ll need to create an account on https://trigger.dev. Once logged in, navigate to Environments -> Development and copy your Secret Key. Paste it into the terminal.
      • 🧠 Important: Your API Key is sensitive. It’s typically stored in an environment variable (like in your .env file) and should never be committed directly to source control. The init command automatically adds it to your .env file for local development.
  • Output: After answering, the CLI will install dependencies and create several files and folders. You should see output similar to:
    ✔ What framework are you using? › Next.js
    ✔ What is your project's root directory? › .
    ✔ What is your API Key? › sk_...
    
    Installing dependencies...
    ... (npm/yarn install output) ...
    
    🎉 Trigger.dev project initialized!
    
    Next steps:
    1. Start your dev server: npm run dev
    2. Go to your Trigger.dev dashboard to see your project: https://app.trigger.dev/orgs/...
    

Step 3: Understanding the Generated Project Structure

Let’s quickly look at the key files and folders the init command created. This gives you a map of your new Trigger.dev project.

  • package.json: Your project’s manifest file, listing scripts (like dev) and dependencies (e.g., @trigger.dev/sdk, @trigger.dev/nextjs).
  • .env: Contains your TRIGGER_SECRET_KEY environment variable. This file is excluded from version control by default.
  • trigger.config.ts: The main configuration file for your Trigger.dev project. This is where you configure things like your API key, base URL, and integrations.
  • src/trigger/client.ts: Exports your initialized Trigger.dev client instance. This client is the bridge between your code and the Trigger.dev platform, used to define and register your jobs.
  • src/trigger/index.ts: This is where you’ll define your Trigger.dev jobs. The init command might have added a sample job here, which we will modify or replace.

Step 4: Creating Your First “Hello World” Job

Now, let’s open src/trigger/index.ts in your code editor and add a very simple job. If there’s already a sample job, you can either modify it or add a new one alongside it.

Open src/trigger/index.ts:

// src/trigger/index.ts
import { trigger } from "./client";
import { eventTrigger } from "@trigger.dev/sdk";

// Define your first Trigger.dev job
trigger.defineJob({
  // A unique identifier for your job.
  // This is how Trigger.dev tracks and manages it across runs.
  id: "hello-world",
  // A human-readable name for your job, visible in the Trigger.dev dashboard.
  name: "Hello World Job",
  // Versioning helps manage changes to your job definitions over time.
  // It allows for graceful updates without breaking in-flight jobs.
  version: "1.0.0",
  // The 'on' property defines what event will trigger this job.
  // Here, we're using eventTrigger to listen for a custom named event.
  on: eventTrigger({
    // The name of the event this job listens for.
    // Events are typically namespaced for clarity (e.g., "user.created", "order.processed").
    name: "hello.world",
  }),
  // The 'run' function contains the actual logic of your job.
  // It's an async function because jobs often involve asynchronous operations
  // like API calls, database interactions, or delays.
  run: async (payload, io, ctx) => {
    // 'io.logger' is a special logger provided by Trigger.dev.
    // Messages logged here will appear in your Trigger.dev dashboard for this specific job run,
    // making debugging distributed workflows much easier than standard console.log.
    io.logger.info("Hello, Trigger.dev!");
    io.logger.info("Received payload:", payload);

    // You can return any data from your job. This data will be stored as the job's output
    // and is visible in the Trigger.dev dashboard.
    return { message: "Success! Hello from your first Trigger.dev job!" };
  },
});

// You can define more jobs here by calling trigger.defineJob again...
// For example:
// trigger.defineJob({
//   id: "another-job",
//   name: "Another Example Job",
//   version: "1.0.0",
//   on: eventTrigger({ name: "another.event" }),
//   run: async (payload, io, ctx) => {
//     io.logger.info("Another job ran!");
//     return { status: "completed" };
//   },
// });
  • import { trigger } from "./client";: This line imports the trigger client instance that was initialized in src/trigger/client.ts. This client is your gateway to defining and interacting with the Trigger.dev platform.
  • import { eventTrigger } from "@trigger.dev/sdk";: This imports the eventTrigger helper. It’s a convenient way to specify that your job should activate when a particular named event is received.
  • trigger.defineJob({...}): This is the core function for defining any Trigger.dev job. It takes a configuration object:
    • id: A unique string identifier. This is crucial for Trigger.dev to track, manage, and display your job in the dashboard.
    • name: A human-readable name for the job, which helps you identify it easily in the Trigger.dev dashboard.
    • version: A semantic version string (e.g., “1.0.0”) for your job’s logic. This is important for durable execution, allowing Trigger.dev to manage different versions of your job gracefully.
    • on: eventTrigger({ name: "hello.world" }): This tells Trigger.dev to run this job whenever an event with the name hello.world is received.
    • run: async (payload, io, ctx) => {...}: This is the heart of your job – the function containing the actual business logic.
      • payload: An object containing the data sent with the incoming event.
      • io: An object providing I/O operations managed by Trigger.dev, such as durable logging (io.logger), performing retriable API calls (io.runTask), and interacting with integrations. This is key for fault tolerance.
      • ctx: Provides contextual information about the current job run, such as ctx.id (the unique ID for this specific run).
    • io.logger.info(...): Unlike console.log, io.logger.info is Trigger.dev’s durable logger. Logs here are captured, associated with the specific job run, and displayed in your Trigger.dev dashboard, making debugging distributed and long-running workflows significantly easier.

Step 5: Running Your Development Server

Now that we’ve defined our job, let’s start the development server. This will register your hello-world job with the Trigger.dev platform and allow it to listen for incoming events.

In your terminal, from your project’s root directory:

npm run dev
  • What’s happening? This script (defined in your package.json) typically starts your Node.js application. The Trigger.dev SDK within your application will connect to the Trigger.dev cloud service using your TRIGGER_SECRET_KEY (from the .env file) and register all the jobs you’ve defined. This connection ensures that Trigger.dev knows about your jobs and can orchestrate their execution.
  • Output: You should see output indicating that your server is running and that Trigger.dev has connected and registered your jobs. Look for messages like “Trigger.dev client connected” and “Registered job: hello-world”. Keep this terminal window open; it’s your local job worker.

Step 6: Triggering Your Job

With your development server running, your hello-world job is now active and waiting for a hello.world event. Let’s trigger it from the Trigger.dev dashboard!

  1. Open the Trigger.dev Dashboard: Go to https://app.trigger.dev and log in.
  2. Navigate to your Project: You should see your project listed on the dashboard. Click on it to enter your project’s overview.
  3. Go to the “Events” Tab: In the left sidebar of your project dashboard, find and click on “Events”.
  4. Send an Event: Click the “Send Event” button (or similar) to manually send an event.
    • Event Name: Type hello.world. This must exactly match the name property you defined in your eventTrigger in src/trigger/index.ts.
    • Payload: You can send some JSON data. For now, let’s keep it simple:
      {
        "greeting": "world"
      }
      
    • Click “Send Event”.
  • Observation:
    • Immediately, your running npm run dev terminal should show your io.logger.info messages: “Hello, Trigger.dev!” and “Received payload: { greeting: ‘world’ }”.
    • In the Trigger.dev dashboard, go to the “Runs” tab. You should see a new entry for your “Hello World Job” with a “Succeeded” status. Click on this run to see the detailed logs, including your io.logger.info messages and the job’s final output.

Congratulations! You’ve successfully set up your Trigger.dev environment, defined a durable job, and seen it execute. This is the foundation for all the powerful workflows you’ll build.

Mini-Challenge: Personalizing Your Greeting

Let’s make our “Hello World” job a little more interactive by using the data from the event payload.

  • Challenge: Modify the hello-world job to accept a name property in its event payload. Instead of just logging “Hello, Trigger.dev!”, it should log a personalized greeting like “Hello, [name] from Trigger.dev!”.

    • Steps:
      1. Open and edit src/trigger/index.ts.
      2. Access the name property from the payload object within the run function.
      3. Update the io.logger.info message to include the personalized name.
      4. Restart your npm run dev server (Ctrl+C to stop, then npm run dev again) to register the updated job definition with Trigger.dev. This step is crucial for changes to take effect.
      5. Trigger the job again from the Trigger.dev dashboard’s “Events” tab, but this time, send a payload like:
        {
          "name": "Alice"
        }
        
  • Hint: The payload object is just a standard JavaScript object. You can access its properties using dot notation (e.g., payload.name). Remember to handle cases where payload.name might not be provided (e.g., use a default greeting).

  • What to observe/learn: This challenge reinforces how to pass dynamic data to your jobs and access it within the run function, which is fundamental for building useful and context-aware workflows. Observe the new personalized greeting in both your terminal and the Trigger.dev dashboard logs for the specific job run.

Common Pitfalls & Troubleshooting

Even simple setups can hit snags. Here are a few common issues you might encounter during initial setup and how to resolve them.

  • npm run dev Not Connecting to Trigger.dev:
    • Symptom: Your terminal shows “Trigger.dev client not connected”, “Failed to connect to Trigger.dev”, or similar errors, and your jobs don’t appear in the dashboard.
    • Cause: The TRIGGER_SECRET_KEY in your .env file is incorrect, has leading/trailing spaces, or is missing. There might also be network issues preventing your local machine from reaching api.trigger.dev, or a firewall blocking outbound connections.
    • Solution: Double-check your TRIGGER_SECRET_KEY against the key displayed in your Trigger.dev dashboard (under Environments -> Development). Ensure there are no extra characters. Verify your internet connection. If on a corporate network, check for proxy settings or firewall rules that might restrict outbound traffic.
  • Job Not Showing in Dashboard / Not Triggering:
    • Symptom: You’ve run npm run dev, and your terminal shows the client connected, but your job doesn’t appear in the dashboard’s “Jobs” list, or sending an event doesn’t cause it to run.
    • Cause: The npm run dev process isn’t actively running, or you haven’t restarted it after making changes to your job definition. The id of your job in trigger.defineJob might not match what you expect, or, most commonly, the eventTrigger name (hello.world) doesn’t exactly match the event name you’re sending from the dashboard (it’s case-sensitive!).
    • Solution: Ensure your npm run dev terminal is active and shows “Registered job: [your-job-id]”. Always restart your dev server (Ctrl+C then npm run dev) after modifying job definitions. Carefully compare the id and eventTrigger.name in your code with how you’re interacting with the dashboard.
  • Node.js Version Errors:
    • Symptom: npm install or npm run dev fails with errors related to Node.js version, such as “Engine ’node’ is incompatible with this module.”
    • Cause: Your installed Node.js version is older than the minimum required (Node.js 18+).
    • Solution: Upgrade Node.js to version 18 or higher using nvm (recommended for managing multiple Node.js versions) or the official installer from nodejs.org.

Summary

In this chapter, you’ve taken the crucial first steps in your Trigger.dev journey! You’ve moved from understanding the concepts to hands-on implementation, laying a solid foundation for more complex workflows.

Here’s a quick recap of what we covered:

  • Environment Setup: We ensured your local development environment was ready, verifying Node.js (v18+) and npm/Yarn installations.
  • Project Initialization: You used the powerful npx trigger.dev@v4-beta init command to scaffold a new Trigger.dev project, setting up essential configuration and client files.
  • Core Concepts: We built a mental model for Trigger.dev by understanding what a job is, how triggers and events work, and the role of the CLI.
  • First Job Creation: You defined a simple “Hello World” job in src/trigger/index.ts, learning about defineJob, eventTrigger, payload, and the durable io.logger.
  • Execution & Observation: You learned how to start your development server with npm run dev and trigger your job manually from the Trigger.dev dashboard, carefully observing its execution and logs.
  • Practical Application: You successfully completed a mini-challenge to personalize your job’s output, reinforcing how to pass and utilize dynamic data.
  • Troubleshooting: We addressed common setup pitfalls like connection issues, job registration problems, and Node.js version mismatches.

You now have a foundational understanding of how to get a Trigger.dev project up and running, and how to define and execute your first durable background job. In the next chapter, we’ll dive deeper into the io object, exploring how to perform external API calls reliably and handle retries, which is essential for building robust AI agents and complex, fault-tolerant workflows.

References

This page is AI-assisted and reviewed. It references official documentation and recognized resources where relevant.