Skip to content

Instantly share code, notes, and snippets.

@inca
Created June 5, 2025 14:57
Show Gist options
  • Save inca/aa182ca54d466d3b611697f1a6f8786e to your computer and use it in GitHub Desktop.
Save inca/aa182ca54d466d3b611697f1a6f8786e to your computer and use it in GitHub Desktop.
Node.js hot module loading: await import cache busting

Hot Module Loading

When loading modules with await import() in Node.js, they become permanently cached. The subsequent await import(url), given the same url will return the exact same module.

If one needs to pick up the changes made to file system, they need custom loader hooks.

For this purpose specifically, only resolve is sufficient (note how mtime is used for cache busting).

Warning! The old modules are never actually reclaimed from memory, so some additional considerations must be taken into account:

  • promises, event listeners, timers and other event loop stuff will coexist between old and new versions of the module and can cause issues, conflicts and very non-intuitive bugs
  • reference equality and instanceof checks will fail between old and new modules (for the same fields)
  • all versions of modules will be kept in cache indefinitely, so memory will grow over time until process is terminated

Conclusion: use at your own risk.

import { stat } from 'node:fs/promises';
import { ResolveFnOutput, ResolveHookContext, } from 'node:module';
import { fileURLToPath } from 'node:url';
type ResolveNext = (specifier: string, context: ResolveHookContext) => Promise<ResolveFnOutput>;
export async function resolve(specifier: string, context: ResolveHookContext, nextResolve: ResolveNext): Promise<ResolveFnOutput> {
const resolved = await nextResolve(specifier, context);
if (!resolved.url.startsWith('file://')) {
return resolved;
}
const file = fileURLToPath(resolved.url);
const { mtime } = await stat(file);
return {
format: resolved.format,
url: resolved.url + `?t=${mtime.getTime()}`,
};
}
import { register } from 'node:module';
register(new URL('./loader.js', import.meta.url));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment