nextjs - 💡(How to fix) Fix JSON files loaded via dynamic import() no longer trigger HMR after upgrading to 16.2 [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#91765Fetched 2026-04-08 01:12:08
View on GitHub
Comments
1
Participants
2
Timeline
4
Reactions
0
Timeline (top)
closed ×1commented ×1labeled ×1locked ×1

Code Example

// src/i18n/messages.ts
const importLocale = async (locale: Locale): Promise<Messages> => {
  return (await import(`../../messages/${locale}.json`)).default as Messages;
};

---

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin 25.3.0

Binaries:
  Node: 22.x
  pnpm: 10.28.0

Relevant Packages:
  next: 16.2.0
  react: 19.2.4
  react-dom: 19.2.4
  next-intl: 4.8.3
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

No public reproduction yet — will create one if needed.

To Reproduce

  1. Use next-intl with dynamic import() to load JSON translation files:
// src/i18n/messages.ts
const importLocale = async (locale: Locale): Promise<Messages> => {
  return (await import(`../../messages/${locale}.json`)).default as Messages;
};
  1. Run next dev (Turbopack, the default in 16.2)
  2. Edit any JSON file under messages/ (e.g., messages/en.json)
  3. Observe that the page does not update — a full server restart is required to see changes

Current vs. Expected behavior

Current (16.2.0): Editing a JSON translation file does not trigger HMR. The dev server shows no recompilation activity. A full restart (next dev) is required to pick up changes.

Expected (worked in 16.1.x): Editing the same JSON file triggered HMR and the page updated automatically without a restart.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin 25.3.0

Binaries:
  Node: 22.x
  pnpm: 10.28.0

Relevant Packages:
  next: 16.2.0
  react: 19.2.4
  react-dom: 19.2.4
  next-intl: 4.8.3

Which area(s) are affected?

Turbopack, HMR

Which stage(s) are affected?

next dev (development)

Additional context

This is a regression from 16.1.x → 16.2.0. JSON translation file HMR worked correctly in 16.1.

The 16.2 release introduced two Turbopack changes that may be related:

  1. Server Fast Refresh — changed from clearing the full require.cache import chain to only reloading the actually-changed module. Dynamic import() with template literal paths (e.g., import(`../../messages/${locale}.json`)) may not be tracked as a dependency, so dependents are not invalidated when the JSON file changes.

  2. Tree Shaking of Dynamic Imports — Turbopack now tree-shakes destructured dynamic imports. This could affect how dynamic JSON imports are tracked in the module graph.

Downgrading to 16.1.x restores the expected HMR behavior.

extent analysis

Fix Plan

To resolve the issue with Hot Module Replacement (HMR) not working for JSON translation files in Next.js 16.2.0, we need to ensure that dynamic imports are properly tracked as dependencies.

Here are the steps to fix the issue:

  • Step 1: Update next-intl configuration We need to configure next-intl to use a custom loader for JSON files. This will allow us to properly track dependencies and enable HMR.

  • Step 2: Create a custom loader Create a new file json-loader.ts with the following content:

import { readFileSync } from 'fs';

export function jsonLoader(filePath: string) {
  const fileContent = readFileSync(filePath, 'utf8');
  return JSON.parse(fileContent);
}
  • Step 3: Update importLocale function Update the importLocale function to use the custom loader:
// src/i18n/messages.ts
import { jsonLoader } from './json-loader';

const importLocale = async (locale: Locale): Promise<Messages> => {
  const filePath = `../../messages/${locale}.json`;
  return jsonLoader(filePath) as Messages;
};
  • Step 4: Add dependency tracking To enable HMR, we need to add dependency tracking for the JSON files. We can do this by using the import.meta.webpackHot API:
// src/i18n/messages.ts
import { jsonLoader } from './json-loader';

const importLocale = async (locale: Locale): Promise<Messages> => {
  const filePath = `../../messages/${locale}.json`;
  const messages = jsonLoader(filePath) as Messages;

  if (import.meta.webpackHot) {
    import.meta.webpackHot.accept(filePath, () => {
      // Update the messages object when the JSON file changes
      messages = jsonLoader(filePath) as Messages;
    });
  }

  return messages;
};

Verification

To verify that the fix worked, follow these steps:

  • Run next dev and edit a JSON translation file.
  • Observe that the page updates automatically without a restart.

Extra Tips

To prevent similar issues in the future, make sure to:

  • Use custom loaders for dynamic imports to ensure proper dependency tracking.
  • Use the import.meta.webpackHot API to enable HMR for dynamic imports.
  • Test HMR functionality thoroughly after updating dependencies or changing configurations.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING