angular/angular-cli · warning

[NG HMR] Cannot find global 'ng'. Likely this is caused beca

Error message

[NG HMR] Cannot find global 'ng'. Likely this is caused because scripts optimization is enabled.

What it means

During Hot Module Replacement the HMR dispose callback (registered in hmr-accept.ts) checks for the Angular testing/global helper object 'ng' in the window scope. When scripts optimization is enabled, the UMD chunks that define the global 'ng' are minified/scope-isolated so the global no longer exists; HMR then logs this warning and aborts the dispose step because it cannot call ng.ɵɵhmr helper APIs.

Source

Thrown at packages/angular_devkit/build_angular/src/tools/webpack/plugins/hmr/hmr-accept.ts:47

declare const Event: any;

export default function (mod: any): void {
  if (!mod['hot']) {
    return;
  }

  if (!isDevMode()) {
    console.error(
      `[NG HMR] Cannot use HMR when Angular is running in production mode. To prevent production mode, do not call 'enableProdMode()'.`,
    );

    return;
  }

  mod['hot'].accept();
  mod['hot'].dispose(() => {
    if (typeof ng === 'undefined') {
      console.warn(
        `[NG HMR] Cannot find global 'ng'. Likely this is caused because scripts optimization is enabled.`,
      );

      return;
    }

    if (!ng.getInjector) {
      // View Engine
      return;
    }

    // Reset JIT compiled components cache
    ɵresetCompiledComponents();
    const appRoot = getAppRoot();
    if (!appRoot) {
      return;
    }

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Disable scripts optimization in the serve configuration: "optimization": { "scripts": false, "styles": true } under configurations/development (or serve options).
  2. Serve with the development configuration: ng serve --configuration development.
  3. If you intentionally optimize scripts, accept that HMR dispose is degraded — this warning is non-fatal; do a full reload instead of relying on HMR state preservation.
  4. Verify the ng global exists at runtime by checking window.ng in devtools; if absent while serving unoptimized, check for scripts that shadow/delete the global.

Example fix

// before (angular.json, serve configuration)
"optimization": true
// => [NG HMR] Cannot find global 'ng'.

// after
"configurations": {
  "development": {
    "optimization": false,
    "hmr": true
  }
}
// ng serve --configuration development
Defensive patterns

Strategy: fallback

Validate before calling

// In the app, verify the ng global exists before relying on HMR state preservation
function hmrViable() {
  return typeof ng !== 'undefined';
}
if (!hmrViable()) {
  console.warn('[NG HMR] global ng missing (scripts optimization on?) — full reload will be used instead of HMR.');
}

Type guard

function hasNgGlobal(win = window) {
  return typeof win['ng'] !== 'undefined';
}

Try / catch

try {
  // HMR update flow
  module.hot.dispose(() => { if (typeof ng === 'undefined') { location.reload(); return; } /* normal dispose */ });
} catch (e) {
  console.warn('[NG HMR] dispose failed, falling back to full reload', e);
  location.reload();
}

Prevention

When it happens

Trigger: mod.hot.dispose callback runs after an HMR update while the global identifier 'ng' is undefined — caused by running ng serve / the dev server with optimization.scripts enabled (e.g. "optimization": true in the serve configuration or NG_BUILD optimization env).

Common situations: 1) Serving with --configuration production (which enables optimization) while expecting HMR. 2) Custom serve configuration that sets "optimization": { "scripts": true }. 3) Copying build options into serve options. 4) HMR proxy setups where optimized vendor chunks hide the ng global.

Related errors


AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30). Data as JSON: /api/errors/c95cc093ebe0f8b3. Report an issue: GitHub.