Inngest
Integrate Inngest with your application for event-driven background workflows.
Inngest is a developer-first platform for building reliable background jobs, scheduled functions, and event-driven workflows. It provides a simple API for creating durable functions that automatically retry on failure.
Why Inngest?
Inngest makes it easy to build reliable background jobs with automatic retries, scheduling, and event-driven workflows. Functions are defined in your codebase and run on Inngest's infrastructure, giving you the reliability of a queue with the simplicity of writing regular functions.
Setup
Visit Inngest and create a free account. Create a new app and note down your signing key.
Add your Inngest credentials to your environment variables:
INNGEST_EVENT_KEY=your_event_key_here
INNGEST_SIGNING_KEY=your_signing_key_hereFor production, make sure to add these environment variables to your deployment platform.
Install dependencies
Install the Inngest SDK:
npm install inngestConfigure Inngest
Create an Inngest client:
import { Inngest } from 'inngest';
import { env } from '@/lib/env';
export const inngest = new Inngest({
id: 'your-app-id',
eventKey: env.INNGEST_EVENT_KEY
});Create your first function
Create functions in a lib/inngest/functions directory:
import { inngest } from '@/lib/inngest';
export const processUserData = inngest.createFunction(
{ id: 'process-user-data' },
{ event: 'user/data.process' },
async ({ event, step }) => {
const { userId, operation } = event.data;
await step.run('process-data', async () => {
console.log('Processing user data', { userId, operation });
switch (operation) {
case 'export':
// Export user data
await new Promise((resolve) => setTimeout(resolve, 2000));
return { success: true, result: 'Data exported to CSV' };
case 'analyze':
// Analyze user data
await new Promise((resolve) => setTimeout(resolve, 5000));
return {
success: true,
result: { totalActions: 156, avgSessionTime: '4m 32s' }
};
case 'cleanup':
// Cleanup user data
await new Promise((resolve) => setTimeout(resolve, 3000));
return { success: true, result: 'Removed 23 obsolete records' };
default:
throw new Error(`Unknown operation: ${operation}`);
}
});
}
);Create a scheduled function:
import { inngest } from '@/lib/inngest';
export const dailyCleanup = inngest.createFunction(
{ id: 'daily-cleanup' },
{ cron: '0 2 * * *' }, // Daily at 2 AM
async ({ step }) => {
await step.run('cleanup-logs', async () => {
console.log('Cleaning up old logs');
await new Promise((resolve) => setTimeout(resolve, 5000));
return { logsCleaned: true };
});
await step.run('cleanup-temp-files', async () => {
console.log('Cleaning up temporary files');
await new Promise((resolve) => setTimeout(resolve, 3000));
return { tempFilesCleaned: true };
});
await step.run('generate-reports', async () => {
console.log('Generating daily reports');
await new Promise((resolve) => setTimeout(resolve, 8000));
return { reportsGenerated: true };
});
}
);Register functions
Create an API route to serve your Inngest functions:
import { serve } from 'inngest/next';
import { inngest } from '@/lib/inngest';
import { dailyCleanup } from '@/lib/inngest/functions/daily-cleanup';
import { processUserData } from '@/lib/inngest/functions/process-user-data';
export const { GET, POST, PUT } = serve({
client: inngest,
functions: [processUserData, dailyCleanup]
});Triggering functions
From an API route
import { NextRequest, NextResponse } from 'next/server';
import * as z from 'zod';
import { getSession } from '@/lib/auth/server';
import { inngest } from '@/lib/inngest';
const processUserDataSchema = z.object({
userId: z.string(),
operation: z.enum(['export', 'analyze', 'cleanup'])
});
export async function POST(request: NextRequest) {
const session = await getSession();
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const body = await request.json();
const { userId, operation } = processUserDataSchema.parse(body);
await inngest.send({
name: 'user/data.process',
data: { userId, operation }
});
return NextResponse.json({
success: true,
message: 'Background task started successfully'
});
}From a server action
'use server';
import { getSession } from '@/lib/auth/server';
import { inngest } from '@/lib/inngest';
export async function processUserData(
userId: string,
operation: 'export' | 'analyze' | 'cleanup'
) {
const session = await getSession();
if (!session) {
throw new Error('Unauthorized');
}
try {
await inngest.send({
name: 'user/data.process',
data: { userId, operation }
});
return { success: true };
} catch (error) {
console.error('Failed to trigger background task:', error);
throw new Error('Failed to start background task');
}
}Monitoring and debugging
Visit the Inngest Dashboard to monitor your functions:
- View function execution logs and performance metrics
- Track success and failure rates
- Monitor function duration and step execution
- Replay failed functions
- Set up alerts for function failures
Best practices
Use step functions for reliability
Break your function into steps using step.run() to make it more reliable and debuggable:
await step.run('step-name', async () => {
// This step will be retried independently if it fails
return await processData();
});Use descriptive function IDs
// ✅ Good
{
id: 'user-data-export-csv';
}
// ❌ Not so good
{
id: 'task1';
}Handle errors gracefully
await step.run('process', async () => {
try {
return await processData();
} catch (error) {
console.error('Processing failed:', error);
throw error; // Re-throw to trigger retry
}
});Next steps
With Inngest integrated into your application, you can now:
- Build reliable background jobs with automatic retries
- Schedule recurring tasks with cron expressions
- Create event-driven workflows that respond to events
- Compose complex workflows using step functions
Ready to explore more? Check out the official documentation for advanced features like function composition, event filtering, and more.