DEV Community

Alex Spinov
Alex Spinov

Posted on

Inngest Has a Free API — Event-Driven Functions with Zero Infrastructure

Inngest lets you build reliable event-driven functions with retries, scheduling, and step functions — all from your existing codebase. No queues, no workers, no infrastructure.

Why Inngest?

  • Zero infrastructure — no Redis, no queues, no workers to manage
  • Step functions — each step is individually retryable
  • Event-driven — trigger functions from events, webhooks, schedules
  • Works everywhere — Next.js, Express, Remix, Deno, Bun

Quick Start

npm install inngest
npx inngest-cli@latest dev  # Local dev server
Enter fullscreen mode Exit fullscreen mode
import { Inngest } from 'inngest';

const inngest = new Inngest({ id: 'my-app' });

// Define a function
export const sendWelcomeEmail = inngest.createFunction(
  { id: 'send-welcome-email' },
  { event: 'user/created' },
  async ({ event, step }) => {
    // Step 1: Get user details
    const user = await step.run('get-user', async () => {
      return await db.getUser(event.data.userId);
    });

    // Step 2: Send email
    await step.run('send-email', async () => {
      await email.send({
        to: user.email,
        subject: 'Welcome!',
        body: `Hello ${user.name}!`,
      });
    });

    // Step 3: Update CRM
    await step.run('update-crm', async () => {
      await crm.addContact(user);
    });
  }
);
Enter fullscreen mode Exit fullscreen mode

Trigger Events

// From your API route
await inngest.send({
  name: 'user/created',
  data: { userId: '123', plan: 'pro' },
});

// Batch events
await inngest.send([
  { name: 'order/placed', data: { orderId: '1' } },
  { name: 'order/placed', data: { orderId: '2' } },
]);
Enter fullscreen mode Exit fullscreen mode

Scheduled Functions (Cron)

export const dailyCleanup = inngest.createFunction(
  { id: 'daily-cleanup' },
  { cron: '0 2 * * *' }, // Every day at 2 AM
  async ({ step }) => {
    await step.run('clean-expired', async () => {
      return await db.deleteExpiredSessions();
    });
    await step.run('send-report', async () => {
      await slack.send('#ops', 'Cleanup complete');
    });
  }
);
Enter fullscreen mode Exit fullscreen mode

Wait for Events

export const onboardingFlow = inngest.createFunction(
  { id: 'onboarding' },
  { event: 'user/created' },
  async ({ event, step }) => {
    // Send welcome email immediately
    await step.run('welcome-email', () => sendWelcome(event.data.userId));

    // Wait up to 24h for profile completion
    const profileEvent = await step.waitForEvent('wait-for-profile', {
      event: 'user/profile-completed',
      match: 'data.userId',
      timeout: '24h',
    });

    if (!profileEvent) {
      // Profile not completed — send reminder
      await step.run('send-reminder', () => sendReminder(event.data.userId));
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Delayed Steps

export const trialReminder = inngest.createFunction(
  { id: 'trial-reminder' },
  { event: 'trial/started' },
  async ({ event, step }) => {
    // Wait 7 days
    await step.sleep('wait-7-days', '7d');

    // Check if converted
    const user = await step.run('check-user', () => getUser(event.data.userId));

    if (!user.isPaid) {
      await step.run('send-reminder', () => sendTrialReminder(user));
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Need event-driven data pipelines? Check out my Apify actors for web scraping that triggers on events, or email spinov001@gmail.com for custom workflows.

Inngest, Trigger.dev, or Temporal — how do you handle workflows? Share below!

Top comments (0)