Urgent.News

What's breaking now, across thousands of outlets.

Tech

NestJS 12 Lifecycle Hooks: The Order You Can't Assume

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…

The problem: a hook order nobody promised

A 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.

The mental model: constructed order vs. hook order

NestJS 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.

Stage 1: the five lifecycle hooks

1. onModuleInit - Called once the host module's dependencies have been resolved.

2. onApplicationBootstrap - Called after all providers in the application have been registered and initialized.

3. onModuleDestroy - Called just before the application is shut down.

4. beforeApplicationShutdown - Called before the application is shut down.

5. onApplicationShutdown - Called once the application has been shut down.

Stage 2: the order Nest does guarantee

NestJS 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.

Stage 3: the order it never guaranteed (and v12 changed)

NestJS 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.

Stage 4: the fix is DI, not a delay

To 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.

Stage 5: shutdown hooks and async hooks

NestJS also provides shutdown hooks (onModuleDestroy, beforeApplicationShutdown, onApplicationShutdown) and async lifecycle hooks. These should be used correctly to handle application shutdown and asynchronous operations properly.

Edge cases and gotchas

When 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.

Best practices

1. Always use dependency injection to establish the required order of execution.

2. Avoid relying on the order of modules in AppModule's imports array.

3. Use shutdown hooks and async lifecycle hooks correctly to handle application shutdown and asynchronous operations.

FAQ

Q: What is the difference between constructed order and hook order?

A: 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.

Q: Why did NestJS change the hook ordering in version 12?

A: 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.

Cheat sheet

1. Lifecycle hooks: onModuleInit, onApplicationBootstrap, onModuleDestroy, beforeApplicationShutdown, onApplicationShutdown.

2. NestJS guarantees: constructor-injection order, not import-position order.

3. Fixing hook-ordering bugs: use dependency injection, not delays or flags.

4. Shutdown hooks: handle application shutdown and asynchronous operations properly.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

Replacing Excel with a Next.js Web App: A Dev's Playbook

Every dev has seen it: a business running its entire operation on a 40-tab Excel file named Orders_FINAL_v2_REAL.xlsx. The 'Excel person' holds it all in their head, formulas break silently, and…

  • AimEncoders developed playbook to replace Excel with modern web apps
  • Data modeling foundation for simplified development process
  • PostgreSQL with row-level permissions ensures reliable operation

Component library - Pebble UX

To the DEV Community, I have been working on a passion project for a while now, and this week I finally hit a major milestone: I published the very first stable version to NPM.

  • Pebble UX is a native, framework-agnostic component library
  • Blazor Bridge enables .NET developers to use Pebble UX components
  • Library focuses on accessibility, themeability, and minimal overhead

Your Custom Hooks Tear in React 18. `useSyncExternalStore` Fixes It.

The header says "You're offline." Three pixels below it, the save button is still clickable, sending requests like nothing's wrong. Same navigator.onLine value. Same render.

  • React 18 introduced useSyncExternalStore to fix tearing issue.
  • useSyncExternalStore allows subscribing to external state without tearing.
  • Include getServerSnapshot for server-side rendering to avoid hydration mismatches.

Day 22 of My Web Development Journey 🚀 | Meta Tags and Introduction to React.js

Today, I learned about HTML meta tags and started exploring React.js. I also learned the difference between a library and a framework and how to set up a React project using the terminal. 1.

  • Meta tags provide webpage information for browsers and search engines
  • React.js is a JavaScript library for building interactive web apps
  • React.js is a library, not a framework, offering reusable components

The .pth file that runs before your code: lessons from the LiteLLM 1.107.0 compromise

The .pth file that runs before your code: lessons from the LiteLLM 1.107.0 compromise Version 1.107.0 of the LiteLLM Python package was published with a credential stealer and a backdoor inside it.

  • .pth file executes Python code before application import, posing security risk
  • LiteLLM 1.107.0 compromise delivered credential stealer and backdoor via compromised GitHub accounts
  • Malicious .pth file triggered credential collector at interpreter start-up

More from Friday 23 October →