Trigger.dev expert for background jobs, AI workflows, and reliable async execution with excellent developer experience and TypeScript-first design. Use when: trigger.dev, trigger dev, background task, ai background job, long running task.
Situation: Long-running AI task or batch process suddenly stops. No error in logs.
Task shows as failed in dashboard but no stack trace. Data partially processed.
Symptoms:
Task fails with no error message
Partial data processing
Works locally, fails in production
"Task timed out" in dashboard
Why this breaks:
Trigger.dev has execution timeouts (defaults vary by plan). When exceeded, the
task is killed mid-execution. If you're not logging progress, you won't know
where it stopped. This is especially common with AI tasks that can take minutes.
Situation: Passing Date objects, class instances, or circular references in payload.
Task queued but never runs. Or runs with undefined/null values.
Symptoms:
Payload values are undefined in task
Date objects become strings
Class methods not available
"Converting circular structure to JSON"
Why this breaks:
Trigger.dev serializes payloads to JSON. Dates become strings, class instances
lose methods, functions disappear, circular refs throw. Your task sees different
data than you sent.
Recommended fix:
Always use plain objects:
// WRONG - Date becomes string
await myTask.trigger({ createdAt: new Date() });
// RIGHT - ISO string
await myTask.trigger({ createdAt: new Date().toISOString() });
// WRONG - Class instance
await myTask.trigger({ user: new User(data) });
// RIGHT - Plain object
await myTask.trigger({ user: { id: data.id, email: data.email } });
// WRONG - Circular reference
const obj = { parent: null };
obj.parent = obj;
await myTask.trigger(obj); // Throws!
In task, reconstitute as needed:
run: async (payload: { createdAt: string }) => {
const date = new Date(payload.createdAt);
// ...
}
Environment variables not synced to Trigger.dev cloud
Severity: CRITICAL
Situation: Task works locally but fails in production. Env var that exists in Vercel
is undefined in Trigger.dev. API calls fail, database connections fail.
Symptoms:
"Environment variable not found"
API calls return 401 in production tasks
Works in dev, fails in production
Database connection errors in tasks
Why this breaks:
Trigger.dev runs tasks in its own cloud, separate from your Vercel/Railway
deployment. Environment variables must be configured in BOTH places. They
don't automatically sync.
Trigger.dev has separate envs - configure staging too
SDK version mismatch between CLI and package
Severity: HIGH
Situation: Updated @trigger.dev/sdk but forgot to update CLI. Or vice versa.
Tasks fail to register. Weird type errors. Dev server crashes.
Symptoms:
Tasks not appearing in dashboard
Type errors in trigger.config.ts
"Failed to register task"
Dev server crashes on start
Why this breaks:
The Trigger.dev SDK and CLI must be on compatible versions. Breaking changes
between versions cause registration failures. The CLI generates types that
must match the SDK.
Recommended fix:
Always update together:
# Update both SDK and CLI
npm install @trigger.dev/sdk@latest
npx trigger.dev@latest dev
# Or pin to same version
npm install @trigger.dev/[email protected]
npx [email protected] dev
Check versions:
npx trigger.dev@latest --version
npm list @trigger.dev/sdk
Situation: Task sends email, then fails on next step. Retry sends email again.
Customer gets 3 identical emails. Or 3 Stripe charges. Or 3 Slack messages.
Symptoms:
Duplicate emails on retry
Multiple charges for same order
Duplicate webhook deliveries
Data inserted multiple times
Why this breaks:
Trigger.dev retries failed tasks from the beginning. If your task has side
effects before the failure point, those execute again. Without idempotency,
you create duplicates.
Situation: Burst of 1000 tasks triggered. All hit OpenAI API simultaneously.
Rate limited. All fail. Retry. Rate limited again. Vicious cycle.
Symptoms:
Rate limit errors (429)
Database connection pool exhausted
API returns "too many requests"
Mass task failures
Why this breaks:
Trigger.dev scales to handle many concurrent tasks. But your downstream
APIs (OpenAI, databases, external services) have rate limits. Without
concurrency control, you overwhelm them.
Recommended fix:
Set queue concurrency limits:
export const callOpenAI = task({
id: 'call-openai',
queue: {
concurrencyLimit: 10, // Only 10 running at once
},
run: async (payload) => {
// Protected by concurrency limit
return await openai.chat.completions.create(payload);
},
});
Situation: Running npx trigger.dev dev but CLI can't find config.
Or config exists but in wrong location (monorepo issue).
Symptoms:
"Could not find trigger.config.ts"
Tasks not discovered
Empty task list in dashboard
Works for one package, not another
Why this breaks:
The CLI looks for trigger.config.ts at the current working directory.
In monorepos, you must run from the package directory, not the root.
Wrong location = tasks not discovered.
monorepo/
├── apps/
│ └── web/
│ ├── trigger.config.ts <- Here, not at monorepo root
│ ├── package.json
│ └── src/trigger/
# Run from package directory
cd apps/web && npx trigger.dev dev
Specify config location:
npx trigger.dev dev --config ./apps/web/trigger.config.ts
wait.for in loops causes memory issues
Severity: MEDIUM
Situation: Processing thousands of items with wait.for between each.
Task memory grows. Eventually killed for memory.
Symptoms:
Task killed for memory
Slow task execution
State blob too large error
Works for small batches, fails for large
Why this breaks:
Each wait.for creates checkpoint state. In a loop with thousands of
iterations, this accumulates. The task's state blob grows until it
hits memory limits.
Recommended fix:
Batch instead of individual waits:
// WRONG - Wait per item
for (const item of items) {
await processItem(item);
await wait.for({ milliseconds: 100 }); // 1000 waits = bloated state
}
// RIGHT - Batch processing
const chunks = chunkArray(items, 50);
for (const chunk of chunks) {
await Promise.all(chunk.map(processItem));
await wait.for({ milliseconds: 500 }); // Only 20 waits
}
For very large datasets, use subtasks:
export const processAll = task({
id: 'process-all',
run: async (payload: { items: string[] }) => {
const chunks = chunkArray(payload.items, 100);
// Each chunk is a separate task
await Promise.all(
chunks.map(chunk =>
processChunk.triggerAndWait({ items: chunk })
)
);
},
});
Using raw SDK instead of Trigger.dev integrations
Severity: MEDIUM
Situation: Using OpenAI SDK directly. API call fails. No automatic retry.
Rate limits not handled. Have to implement all resilience manually.
Symptoms:
Manual retry logic in tasks
Rate limit errors not handled
No automatic logging of API calls
Inconsistent error handling
Why this breaks:
Trigger.dev integrations wrap SDKs with automatic retries, rate limit
handling, and proper logging. Using raw SDKs means you lose these
features and have to implement them yourself.
Recommended fix:
Use integrations when available:
// WRONG - Raw SDK
import OpenAI from 'openai';
const openai = new OpenAI();
// RIGHT - Trigger.dev integration
import { openai } from '@trigger.dev/openai';
const openaiClient = openai.configure({
id: 'openai',
apiKey: process.env.OPENAI_API_KEY,
});
// Now has automatic retries and rate limiting
export const generateContent = task({
id: 'generate-content',
run: async (payload) => {
const response = await openaiClient.chat.completions.create({
model: 'gpt-4-turbo-preview',
messages: [{ role: 'user', content: payload.prompt }],
});
return response;
},
});
Available integrations:
@trigger.dev/openai
@trigger.dev/anthropic
@trigger.dev/resend
@trigger.dev/slack
@trigger.dev/stripe
Triggering tasks without dev server running
Severity: MEDIUM
Situation: Called task.trigger() but nothing happens. No errors either.
Task just disappears into void. Dev server wasn't running.
Symptoms:
Triggers don't run
No task in dashboard
No errors, just silence
Works in production, not dev
Why this breaks:
In development, tasks run through the local dev server (npx trigger.dev dev).
If it's not running, triggers queue up or fail silently depending on
configuration. Production works differently.
Recommended fix:
Always run dev server during development:
# Terminal 1: Your app
npm run dev
# Terminal 2: Trigger.dev dev server
npx trigger.dev dev
Check dev server is connected:
Should show "Connected to Trigger.dev"
Tasks should appear in console
Dashboard shows task registrations
In package.json:
{
"scripts": {
"dev": "next dev",
"trigger:dev": "trigger.dev dev",
"dev:all": "concurrently \"npm run dev\" \"npm run trigger:dev\""
}
}
Validation Checks
Task without logging
Severity: WARNING
Message: Task has no logging. Add logger.log() calls for debugging in production.
Fix action: Import { logger } from '@trigger.dev/sdk/v3' and add log statements
Task without error handling
Severity: ERROR
Message: Task lacks explicit error handling. Unhandled errors may cause unclear failures.
Fix action: Wrap task logic in try/catch and log errors with context
Task without concurrency limit
Severity: WARNING
Message: Task has no concurrency limit. High load may overwhelm downstream services.
Fix action: Add queue: { concurrencyLimit: 10 } to protect APIs and databases
Date object in trigger payload
Severity: ERROR
Message: Date objects are serialized to strings. Use ISO string format instead.
Fix action: Use date.toISOString() instead of new Date()
Class instance in trigger payload
Severity: ERROR
Message: Class instances lose methods when serialized. Use plain objects.
Fix action: Convert class instance to plain object before triggering
Task without explicit ID
Severity: ERROR
Message: Task must have an explicit id property for registration.
Fix action: Add id: 'my-task-name' to task definition
Trigger.dev API key hardcoded
Severity: CRITICAL
Message: Trigger.dev API key should not be hardcoded - use TRIGGER_SECRET_KEY env var
Fix action: Remove hardcoded key and use process.env.TRIGGER_SECRET_KEY
Using raw OpenAI SDK instead of integration
Severity: WARNING
Message: Consider using @trigger.dev/openai for automatic retries and rate limiting
Fix action: Replace with: import { openai } from '@trigger.dev/openai'
Using raw Anthropic SDK instead of integration
Severity: WARNING
Message: Consider using @trigger.dev/anthropic for automatic retries and rate limiting
Fix action: Replace with: import { anthropic } from '@trigger.dev/anthropic'
wait.for inside loop
Severity: WARNING
Message: wait.for in loops creates many checkpoints. Consider batching instead.
Fix action: Batch items and use fewer waits, or split into subtasks