In the last lesson, three separate methods all subscribed to the same event, each getting a chance to react in a specific order: Mario first, then Batman, then a generic fallback. That ordering wasn't an accident — it was controlled by a priority number attached to each subscription. This lesson is about that number, and why getting it right matters whenever more than one piece of code cares about the same event.
What you'll learn in this lesson
- Where the priority number goes in
getSubscribedEvents(), and what its default is - Why higher numbers run first, not last
- How priority interacts with
stopPropagation()across subscribers in different modules - A sensible convention for choosing your own priority values
The priority slot in getSubscribedEvents()
public static function getSubscribedEvents(): array {
$events[IncidentEvents::NEW_REPORT][] = ['notifyMario']; // priority 0 (default)
$events[IncidentEvents::NEW_REPORT][] = ['notifyBatman', -100]; // explicit priority
$events[IncidentEvents::NEW_REPORT][] = ['notifyDefault', -255];
return $events;
}
Each entry in the array is a two-element list: the method name, and an optional integer priority. Omit the priority and it defaults to 0. notifyMario() above has no explicit priority, so it's 0; notifyBatman() is -100, lower than Mario's; notifyDefault() is lower still at -255.
Higher numbers go first — this trips people up
The rule is: higher priority runs earlier. With the values above, execution order is Mario (0) → Batman (-100) → default (-255) — from highest number to lowest. It's easy to assume "priority 1" means "the first one to run, like a queue position," but it's really more like a scoreboard: whoever has the highest number goes first. If you want something to run before everything else Drupal core does for a given event, you'll often see values like 256 or higher in contributed modules; to run dead last, very negative numbers like -1000.
100 on KernelEvents::REQUEST has no relationship whatsoever to a priority of 100 on your own custom event — they're only ever compared against other subscribers listening to that exact same event name. There's no cross-event ordering to reason about.Why priority matters most when stopPropagation() is involved
Picture two contributed modules both subscribing to the same event: one wants to log every incident, the other wants to short-circuit and stop propagation for a specific type. If the short-circuiting subscriber happens to run before the logger (because it has a higher priority), the logger never runs at all for that incident — silently. This is the single biggest reason priority bugs are hard to track down: nothing errors, a subscriber just quietly never gets its turn. When you call stopPropagation() in your own code, you're making an implicit promise about ordering to every other module that might subscribe to the same event, forever.
Quick check: two subscribers listen to the same event — Subscriber A at priority
10, Subscriber B with no priority specified. Which one runs first? (Answer: Subscriber A. No priority means the default of0, and10 > 0, so A runs first — this is true regardless of which subscriber's class or module was registered first.)
Key takeaways
- Priority is the optional second element of each
[method, priority]pair ingetSubscribedEvents(); omitting it defaults to0. - Higher numbers run first — this is the opposite of what a "priority 1, 2, 3" queue intuition suggests.
- Priority only orders subscribers listening to the exact same event — it has no meaning across different events.
- A subscriber that calls
stopPropagation()can silently prevent lower-priority subscribers — including ones in modules you don't control — from ever running. Reach for it deliberately, not as a default.
Coming up next
You've now covered Drupal's full event system, from listening to core events through defining, dispatching, subscribing to, and ordering your own. Next, the tutorial shifts to a different foundational API: reading and writing your module's own data directly against the database.