Skills

Webiny Event Handler Pattern

EventHandler implementation pattern, handle method, event payloads, filtering, DI...

Install

npx skills add webiny/webiny-js --skill webiny-event-handler-pattern -g -a claude-code -y
Repository
webiny/webiny-js8.1k
Category
Engineering
Updated
5d ago
License
See repository
Context cost
Mediumabout 2,691 tokens
Runs scripts
No, instructions only

What it does

EventHandler implementation pattern, handle method, event payloads, filtering, DI, domain event definition, publishing events from UseCases, and reacting to external events. Use this skill to implement any Webiny EventHandler (before/after hooks) or to define and publish your own domain events.

EventHandler Pattern

What It Is

An EventHandler reacts to domain events in the Webiny lifecycle (e.g., EntryBeforeCreateEventHandler, TenantAfterDeleteEventHandler). Each handler is a DI abstraction with a single handle method.

Naming Convention

  • {Entity}Before{Operation}EventHandler, fires before persistence, can validate/transform/reject
  • {Entity}After{Operation}EventHandler, fires after persistence, for side effects

Interface Shape

interface SomeEventHandler.Interface {
    handle(event: SomeEventHandler.Event): Promise<void>;
}

The Event is a DomainEvent<Payload> where the payload contains the entity and input data.

Architecture Rule: Always Wrap Logic in a Reusable Abstraction (MANDATORY)

Never put business logic directly inside an EventHandler. EventHandlers are thin orchestrators, they receive an event and delegate to an injected service or use case. The real logic lives in a dedicated abstraction.

Why: Inline handler logic cannot be reused by other handlers, GraphQL resolvers, or CLI commands.

Always follow this structure:

features/
├── myService/             ← the reusable abstraction
│   ├── abstractions.ts
│   ├── feature.ts
│   └── MyService.ts
└── syncOnCreate/          ← thin handler that injects the service
    ├── feature.ts
    └── EntryAfterCreateHandler.ts

The EventHandler feature and the service feature are registered separately in Extension.ts.

How to Implement

import { SomeEventHandler } from "webiny/api/<category>";
import { MyService } from "../myService/abstractions.js";

// ✅ Handler is a thin orchestrator, no business logic here
class MyHandler implements SomeEventHandler.Interface {
  constructor(private myService: MyService.Interface) {}

  async handle(event: SomeEventHandler.Event) {
    const { entity, model } = event.payload;

    // For CMS handlers: ALWAYS filter by model
    if (model.modelId !== "myModel") return;
Read the whole SKILL.md on GitHub

More in Engineering