Skip to main content

nestjs-inngest-transport

Inngest as a NestJS microservice transport. Your @EventPattern handlers become durable Inngest functions, and a ClientProxy sends the events that trigger them.

@Controller()
@UseFilters(InngestExceptionFilter)
export class OrdersHandler {
@InngestEventPattern('orders.placed', { concurrency: { limit: 5 } })
async place(@Payload() order: Order, @Ctx() context: InngestContext) {
const step = context.getStep();
await step.run('reserve-stock', () => this.stock.reserve(order));
await step.sleep('cool-off', '1h');
await step.run('confirm', () => this.mailer.confirm(order));
}
}

The idea​

Nest's microservices give one programming model — @EventPattern, @Payload(), @Ctx(), ClientProxy.emit() — over many brokers: Redis, NATS, RabbitMQ, Kafka. This package adds Inngest to that list as a custom transport.

From the controller's side nothing is new: guards, pipes, interceptors and exception filters apply as on any transport. What Inngest adds is what a queue does not have: durable steps that run once and are memoized across retries, step.sleep and step.waitForEvent, retries with backoff, concurrency, throttling, rate limiting, debouncing, idempotency, and a dashboard of every run.

How it maps​

NestInngest
@EventPattern('orders.placed')a function triggered by the orders.placed event
@Payload()the event's data
@Ctx() → InngestContextthe event, the step tools, the run id, the attempt
ClientProxy.emit(pattern, data)inngest.send({ name: pattern, data })
a handler that throwsa failed attempt, retried by Inngest
@InngestEventPattern(pattern, config)the function's configuration

Two things that are different​

Inngest is not a broker you poll, and two consequences shape how this transport is set up:

  1. Inngest calls you. A function is invoked over HTTP, so the strategy mounts on your application's HTTP server — Express or Fastify — and the application has to be reachable by Inngest. See Express and Fastify and Deployment.
  2. Triggers are exact names. Inngest has no wildcards, so a pattern is resolved into the event names it stands for when the functions are created. See Patterns and triggers.

Where to go next​