DEV Community

Alex Spinov
Alex Spinov

Posted on

Inngest Has a Free API You Should Know About

Inngest turns events into reliable, durable functions — no queues, no workers, no infrastructure.

Define a Function

import { inngest } from './client'

export const sendWelcomeEmail = inngest.createFunction(
  { id: 'send-welcome-email' },
  { event: 'user/signed.up' },
  async ({ event, step }) => {
    // Step 1: Wait 1 hour
    await step.sleep('wait-before-email', '1h')

    // Step 2: Send email (auto-retried on failure)
    await step.run('send-email', async () => {
      await resend.emails.send({
        to: event.data.email,
        subject: 'Welcome!',
        html: '<h1>Welcome aboard!</h1>'
      })
    })

    // Step 3: Update user record
    await step.run('update-user', async () => {
      await db.user.update({
        where: { id: event.data.userId },
        data: { welcomeEmailSent: true }
      })
    })
  }
)
Enter fullscreen mode Exit fullscreen mode

Send Events

import { inngest } from './client'

// From your API route
export async function POST(request) {
  const user = await createUser(request)

  // Send event — triggers all matching functions
  await inngest.send({
    name: 'user/signed.up',
    data: { userId: user.id, email: user.email }
  })

  return Response.json(user)
}
Enter fullscreen mode Exit fullscreen mode

Step Functions — Durable Execution

export const processOrder = inngest.createFunction(
  { id: 'process-order', retries: 5 },
  { event: 'order/created' },
  async ({ event, step }) => {
    // Each step is independently retried
    const payment = await step.run('charge-payment', async () => {
      return stripe.charges.create({ amount: event.data.total })
    })

    // Wait for external event (webhook from shipping provider)
    const shipment = await step.waitForEvent('wait-for-shipment', {
      event: 'shipment/created',
      match: 'data.orderId',
      timeout: '7d'
    })

    // Continue after shipment confirmed
    await step.run('send-tracking', async () => {
      await sendTrackingEmail(event.data.email, shipment.data.trackingNumber)
    })
  }
)
Enter fullscreen mode Exit fullscreen mode

Fan-out Pattern

export const batchProcess = inngest.createFunction(
  { id: 'batch-process' },
  { event: 'batch/uploaded' },
  async ({ event, step }) => {
    const items = await step.run('parse-file', () => parseCSV(event.data.fileUrl))

    // Fan-out: send an event for each item
    await step.sendEvent('fan-out', 
      items.map(item => ({
        name: 'item/process',
        data: item
      }))
    )
  }
)
Enter fullscreen mode Exit fullscreen mode

Real-World Use Case

An e-commerce platform had a brittle order pipeline: if email sending failed, the whole order processing crashed. With Inngest, each step retries independently. If Stripe is down, it retries charging. If the email service fails, the order is still processed. They went from 5% failed orders to 0.01%.

Inngest makes complex workflows feel like writing a simple function.


Build Smarter Data Pipelines

Need to scrape websites, extract APIs, or automate data collection? Check out my ready-to-use scrapers on Apify — no coding required.

Custom scraping solution? Email me at spinov001@gmail.com — fast turnaround, fair prices.

Top comments (0)