Events Rules
Defines Trigger.dev event processing conventions with typed payloads, error handling, logging, and timeout guidelines.
What this file does
Defines Trigger.dev event processing conventions with typed payloads, error handling, logging, and timeout guidelines.
When to use it
- Adopting Trigger.dev for background tasks in a TypeScript project
- Standardising event naming and file organisation across a team
- Enforcing typed payloads and structured error handling in event handlers
- Setting up event-driven integrations with external services like email
Assumes this stack
trigger: always_on
Events Rules
Event Processing Framework
MUST use Trigger.dev for event processing and background tasks.
Event Definition Pattern:
// src/services/trigger/events/UserCreatedEvent.ts
import { logger, task } from "@trigger.dev/sdk";
import User from "@/domain/entities/User";
export const UserCreatedEvent = task({
id: "UserCreatedEvent",
maxDuration: 300, // Stop after 300 secs (5 mins)
run: async (payload: Partial<User>, { ctx }) => {
logger.log("Processing user creation", { payload, ctx });
// Event processing logic here
await processUserCreation(payload);
},
});
export default UserCreatedEvent;
Event Organization
MUST place event definitions in src/services/trigger/events/ directory.
MUST use PascalCase for event names ending with "Event":
UserCreatedEvent.tsOrderProcessedEvent.tsPaymentCompletedEvent.ts
Event Structure Requirements
MUST include these properties in every event:
export const EventName = task({
id: "EventName", // Unique identifier matching the export name
maxDuration: 300, // Timeout in seconds
run: async (payload: PayloadType, { ctx }) => {
// Event processing logic
},
});
MUST use typed payload parameters based on domain entities:
run: async (payload: Partial<User>, { ctx }) => {
// payload is properly typed
};
Event Payload Rules
MUST use domain entity types or Partial<Entity> for payloads:
// Good: Uses domain entity
run: async (payload: Partial<User>, { ctx }) => { ... }
// Good: Uses specific type
interface OrderPayload {
orderId: string;
userId: string;
amount: number;
}
run: async (payload: OrderPayload, { ctx }) => { ... }
MUST NOT use any or overly generic types for payloads.
Logging Requirements
MUST use Trigger.dev logger for all event logging:
import { logger } from "@trigger.dev/sdk";
// Log event start
logger.log("Event started", { payload, ctx });
// Log progress
logger.info("Processing step completed", { step: "validation" });
// Log errors
logger.error("Event failed", { error: error.message });
// Log completion
logger.log("Event completed successfully", { result });
Error Handling in Events
MUST handle errors gracefully in event processors:
run: async (payload: Partial<User>, { ctx }) => {
try {
await processUserCreation(payload);
logger.log("User creation processed successfully");
} catch (error) {
logger.error("Failed to process user creation", {
error: error.message,
userId: payload.id,
});
throw error; // Re-throw to trigger retry mechanism
}
};
Event Triggers
MUST trigger events from service layer, not directly from controllers:
// src/services/auth/AuthService.ts
import UserCreatedEvent from "@/services/trigger/events/UserCreatedEvent";
class AuthService {
async createUser(userData: Partial<User>): Promise<User> {
const user = await userRepository.create(userData);
// Trigger event after successful creation
await UserCreatedEvent.trigger(user);
return user;
}
}
Integration with External Services
MUST handle external service integrations within event handlers:
// Integration with email service
export const UserCreatedEvent = task({
id: "UserCreatedEvent",
maxDuration: 300,
run: async (payload: Partial<User>, { ctx }) => {
logger.log("Sending welcome email", { userId: payload.id });
const { data, error } = await resend.emails.send({
from: "no-reply@yourapp.com",
to: [payload.email!],
subject: "Welcome to our platform",
html: `<h1>Welcome ${payload.firstName}!</h1>`,
});
if (error) {
logger.error("Failed to send welcome email", {
error,
userId: payload.id,
});
throw new Error(`Email sending failed: ${error.message}`);
}
logger.log("Welcome email sent successfully", {
messageId: data?.id,
userId: payload.id,
});
},
});
Event Configuration
MUST configure Trigger.dev in project configuration:
// trigger.config.ts
import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "your-project-id",
// other configuration
});
MUST include trigger script in package.json:
{
"scripts": {
"trigger": "npx trigger.dev@latest dev"
}
}
Event Naming Conventions
Event IDs MUST match the export name:
export const UserCreatedEvent = task({
id: "UserCreatedEvent", // Must match export name
// ...
});
Event files MUST use PascalCase with "Event" suffix:
- File:
UserCreatedEvent.ts - Export:
UserCreatedEvent - ID:
"UserCreatedEvent"
Event Dependencies
MUST import required services and repositories at the top:
import { logger, task } from "@trigger.dev/sdk";
import User from "@/domain/entities/User";
import resend from "@/services/resend";
import db from "@/persistance/db";
MUST avoid circular dependencies between events and services.
Event Timeouts
MUST set appropriate maxDuration based on event complexity:
- Simple events: 60-300 seconds
- Complex processing: 300-900 seconds
- Long-running tasks: 900+ seconds
Example timeout guidelines:
// Email sending
maxDuration: 60,
// Data processing
maxDuration: 300,
// File uploads/downloads
maxDuration: 900,
Event Testing
MUST create testable event handlers by extracting logic:
// Testable business logic
export const processUserCreation = async (user: Partial<User>) => {
// Business logic here
return await sendWelcomeEmail(user);
};
// Event handler delegates to business logic
export const UserCreatedEvent = task({
id: "UserCreatedEvent",
maxDuration: 300,
run: async (payload: Partial<User>, { ctx }) => {
logger.log("Processing user creation", { payload });
return await processUserCreation(payload);
},
});
What's inside
14 sections covering event definition, organisation, payload rules, logging, error handling, triggers, integrations, config, naming, dependencies, timeouts, and testing
Change this for your project
- Replace
"your-project-id"with your actual Trigger.dev project ID - Replace
"no-reply@yourapp.com"with your sender email address - Replace
"your-app-name"in the welcome email subject with your app name
Where it goes
Keep in docs/ or alongside the feature. Agents read it to implement against a defined contract.
Worth borrowing
- Extract business logic into separate testable functions, keeping event handlers as thin delegates
- Use domain entity types (e.g.
Partial<User>) for event payloads instead of generic types
Related Documents
Community AI Agent Skills Discovery Sources
Catalogs 50+ platforms, repositories, directories, and communities for discovering and sharing AI agent skills across multiple coding tools.
GPU Selection Guide for Large Language Models (LLMs)
Guides GPU selection for LLM inference, fine-tuning, and training by mapping model sizes, precision levels, and budgets to VRAM requirements.
ReleaseKit - Technical Requirements Document
Specifies a Go library and CLI for release automation with conventional commit parsing, validation checks, and workflow orchestration.
Python Development Environment Setup with Ruff
Defines a complete Python development environment using Ruff for linting and formatting, with pytest, mypy, pre-commit hooks, and VSCode configuration.