vercel/next.js · error · Error

hmrRefresh can only be used in development mode. Please use

Error message

hmrRefresh can only be used in development mode. Please use refresh instead.

What it means

`router.hmrRefresh()` is a development-only method that triggers Hot Module Replacement for the current route. It throws unconditionally when `process.env.NODE_ENV !== 'development'` because HMR infrastructure does not exist in production builds. The error message directs you to use `router.refresh()` instead, which works in all environments.

Source

Thrown at packages/next/src/client/components/app-router-instance.ts:486

        options?.scroll === false
          ? ScrollBehavior.NoScroll
          : ScrollBehavior.Default,
        null,
        options?.transitionTypes,
        null
      )
    })
  },
  refresh: () => {
    startTransition(() => {
      dispatchAppRouterAction({
        type: ACTION_REFRESH,
      })
    })
  },
  hmrRefresh: () => {
    if (process.env.NODE_ENV !== 'development') {
      throw new Error(
        'hmrRefresh can only be used in development mode. Please use refresh instead.'
      )
    } else {
      // Reset the known routes table so that route predictions are cleared
      // when routes change during development.
      resetKnownRoutes()
      let signal: AbortSignal | undefined
      if (process.env.__NEXT_SERVER_COMPONENTS_HMR_CANCELLATION) {
        // Abort the superseded generation before scheduling the new one, so its
        // request is torn down as early as possible. Halting (not rejecting)
        // makes the abort safe regardless of order.
        activeHmrRefreshController?.abort()
        activeHmrRefreshController = new AbortController()
        signal = activeHmrRefreshController.signal
      }
      startTransition(() => {
        dispatchAppRouterAction({
          type: ACTION_HMR_REFRESH,

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Use `router.refresh()` instead — it works in all environments.
  2. Guard the call: `if (process.env.NODE_ENV === 'development') router.hmrRefresh()`.
  3. Remove the hmrRefresh call from code paths that run in production.

Example fix

// before — throws in production
router.hmrRefresh()

// after — use refresh (works everywhere)
router.refresh()
// or guard the dev-only method:
if (process.env.NODE_ENV === 'development') {
  router.hmrRefresh()
}
Defensive patterns

Strategy: validation

Validate before calling

function safeHmrRefresh(router: { hmrRefresh: () => void; refresh: () => void }): void {
  if (process.env.NODE_ENV === 'development') {
    router.hmrRefresh()
  } else {
    router.refresh()
  }
}

Type guard

function isDev(): boolean {
  return process.env.NODE_ENV === 'development'
}

Prevention

When it happens

Trigger: Calling `router.hmrRefresh()` in code that executes during a production build (`next build`) or production server (`next start`).

Common situations: Dev-only debugging code left in a production code path; a custom dev toolbar or plugin that calls hmrRefresh without environment checks; shared utility code used in both dev and prod.

Related errors


AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06). Data as JSON: /api/errors/cd26a8901d1f7ff7. Report an issue: GitHub.