{
  "id": 16156659,
  "title": "NestJS 12 Lifecycle Hooks: The Order You Can't Assume",
  "url": "https://urgent.news/2026/10/23/nestjs-12-lifecycle-hooks-the-order-you-cant-assume",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-10-23T06:10:31.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/parsajiravand/nestjs-12-lifecycle-hooks-the-order-you-cant-assume-amn"
  },
  "original_language": "en",
  "account": "The problem: a hook order nobody promised\nA NestJS application upgraded from version 11 to 12 by installing the latest versions of @nestjs/core and @nestjs/common packages. However, the test suite, which had been working fine for months, began to fail intermittently. In this scenario, a report service was reading a cache that a metrics service was supposed to populate, but about one out of every three runs, the cache had not been populated. The issue was that the order of execution for lifecycle hooks had changed, causing unexpected behavior.\n\nThe mental model: constructed order vs. hook order\nNestJS provides five lifecycle hooks: onModuleInit, onApplicationBootstrap, onModuleDestroy, beforeApplicationShutdown, and onApplicationShutdown. These hooks are implemented in providers (or modules) by opting into them through the appropriate interface. The order of hook execution is crucial, especially when one hook depends on another.\n\nStage 1: the five lifecycle hooks\n1. onModuleInit - Called once the host module's dependencies have been resolved.\n2. onApplicationBootstrap - Called after all providers in the application have been registered and initialized.\n3. onModuleDestroy - Called just before the application is shut down.\n4. beforeApplicationShutdown - Called before the application is shut down.\n5. onApplicationShutdown - Called once the application has been shut down.\n\nStage 2: the order Nest does guarantee\nNestJS guarantees that if provider B is constructor-injected into provider A, it will always construct B and run B's onModuleInit before constructing and running A's. This is a structural guarantee based on constructor injection, and it remains consistent across versions.\n\nStage 3: the order it never guaranteed (and v12 changed)\nNestJS does not guarantee any specific order for two providers that share no dependency edges and are in sibling modules that never import each other. This was not explicitly promised in the public API, and it was an accident that the order remained stable in previous versions. The upgrade to NestJS 12 changed this assumption, breaking code that relied on a specific ordering.\n\nStage 4: the fix is DI, not a delay\nTo fix the hook-ordering bug, developers should use dependency injection instead of relying on delays or flags. By injecting one provider into another, NestJS can ensure that the proper order of execution is maintained.\n\nStage 5: shutdown hooks and async hooks\nNestJS also provides shutdown hooks (onModuleDestroy, beforeApplicationShutdown, onApplicationShutdown) and async lifecycle hooks. These should be used correctly to handle application shutdown and asynchronous operations properly.\n\nEdge cases and gotchas\nWhen relying on hook order, developers must express their dependencies as constructor parameters instead of inferring them from import positions. This ensures that the proper order of execution is maintained.\n\nBest practices\n1. Always use dependency injection to establish the required order of execution.\n2. Avoid relying on the order of modules in AppModule's imports array.\n3. Use shutdown hooks and async lifecycle hooks correctly to handle application shutdown and asynchronous operations.\n\nFAQ\nQ: What is the difference between constructed order and hook order?\nA: Constructed order is guaranteed by NestJS when one provider is constructor-injected into another. Hook order, on the other hand, is not guaranteed and can change based on the internal bootstrap process.\n\nQ: Why did NestJS change the hook ordering in version 12?\nA: The change was made to remove an accidental dependency on a specific order that was never officially guaranteed. This change improves the reliability of the framework by removing assumptions about hook order.\n\nCheat sheet\n1. Lifecycle hooks: onModuleInit, onApplicationBootstrap, onModuleDestroy, beforeApplicationShutdown, onApplicationShutdown.\n2. NestJS guarantees: constructor-injection order, not import-position order.\n3. Fixing hook-ordering bugs: use dependency injection, not delays or flags.\n4. Shutdown hooks: handle application shutdown and asynchronous operations properly.",
  "summary": "A NestJS app upgrades from v11 to v12. No application code changes — just npm i @nestjs/core@latest @nestjs/common@latest . The test suite, which has been green for months, starts failing intermittently: a report service reads a cache that a metrics service is supposed to have already populated, and about one run in three, it hasn't been. Nothing in the diff touches either service. The bug was…",
  "key_points": [],
  "editors_take": "The removal of accidental ordering guarantees in NestJS 12 forces developers to use explicit dependency injection to prevent intermittent failures caused by unlinked sibling modules.",
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}