Angular SyntaxError Cannot Use Import Statement Outside A Module | Fix Fast

This Angular error appears when ES import code runs as non-ES modules, so Node, TypeScript, and your runner must agree on one module mode.

You see this message when a runtime reads an import statement and loads the file as CommonJS. In Angular work, that runtime is often Node, or a Node-based tool like Jest, ts-node, or an SSR server entry. Your browser bundle can look fine while a Node path is failing behind the scenes.

Angular apps live in two worlds. Your app code ships to the browser as bundled JavaScript. Your build steps, tests, scripts, and SSR run in Node. Bundlers handle imports on the browser side. Node has stricter module rules, so this error tends to show up there.

The goal is simple. Find the first file that threw, then make sure the file is executed under the module rules it was written for. You can fix this by going all-in on CommonJS for Node code, or by moving Node code to ESM. Either path works when you keep the signals consistent.

Why This Error Shows Up In Angular Projects

This error is not about Angular templates or DI. It’s about a mismatch between syntax and the loader. A file contains ESM syntax, but Node treats it as CommonJS, so the parser bails out.

The stack trace often points at one of three places: a file you run with Node, a test runner file, or a dependency pulled in during tests. Once you know which bucket it is, the next step is narrow and mechanical.

Where You See It What It Usually Means First Fix To Try
Node script, SSR, or server entry Node loaded a file as CommonJS Align package.json type and TS module output
Jest test run Jest skipped transforms for an ESM file Adjust transforms and transformIgnorePatterns
ts-node / dev script ts-node mode and tsconfig disagree Run ts-node in ESM mode or compile to CJS

Fixing Angular SyntaxError Cannot Use Import Statement Outside A Module In Angular CLI Projects

Start by finding the first file in the stack trace that contains the import token. That file is the one being executed in the wrong mode. The rest of the stack is just the domino effect.

Find The Real Entry File

Don’t start by rewriting imports. Start by confirming what file the runner executed. One clear way is to look at the first stack entry that is not inside Node internals. If it points at dist/, you are running compiled output. If it points at node_modules/, a dependency is being loaded without the right transform. If it points at a .ts file, a tool is trying to run TypeScript directly.

  • Read The First Userland Path — Use the first real file path in the stack to decide if the failure came from build output, a test, or a script.
  • Check The Extension.mjs signals ESM, .cjs signals CommonJS, and plain .js follows package rules.
  • Match The Command — Note the exact command that fails, then rerun only that command after each change.

Pick One Module Direction For Node Code

You can fix this in two clean ways. The trick is not mixing them by accident.

  • Stay CommonJS In Node — Compile TypeScript to CommonJS for scripts, SSR, and tests, then run the compiled output with Node.
  • Move Node To ESM — Mark the Node-run part of the repo as ESM, keep TypeScript output in an ESM-friendly mode, then configure tests to handle ESM.

If your Angular app builds fine and only a Node command fails, it’s a strong sign you only need to change the Node side. If Jest fails but Karma works, it’s a strong sign the Jest transform rules are the gap.

Check Where The File Runs And What Loads It

The same source file can be handled by different tools. Angular CLI bundles browser code. Node runs server code. Jest runs tests in Node. Karma runs tests in a browser. When you name the runner, the fix becomes obvious.

When A Plain Node Command Fails

If the failing command starts with node, the problem is Node module rules. Node permits import only when the file is treated as an ES module. That can be decided by file extensions, package settings, or explicit flags.

  • Confirm You Are Not Running TS — If you run a .ts file with Node, you need a loader or a build step first.
  • Check The Nearest package.json — Node’s module mode can change based on the closest package.json file that applies to the executed file.
  • Open The Executed JS — If the executed file still contains import lines, your build step is not emitting the format you expect.

When SSR Fails

SSR stacks often blend build output and Node runtime code. If you build server output as ESM but run it as CommonJS, this error shows up. If you build it as CommonJS but a dependency is ESM-only, it can show up too. The stack trace will tell you which layer to adjust.

When It Only Happens In Tests

If the app runs fine in the browser but tests fail, focus on the test runner. Jest, in particular, may skip transforming files in node_modules. That is fine for older CommonJS packages, but it can break when a dependency ships ESM.

Align TypeScript, File Extensions, And package.json

Three signals decide how Node parses your code: file extension, the closest package.json module type, and the JavaScript that TypeScript emits. A mismatch in any one of these can trigger the error.

Option A Keep Node Code CommonJS

This path is a good fit when your scripts already use require or when a tool expects CommonJS. You write TypeScript with imports, then compile to CommonJS before Node runs it. Node never sees import syntax, so the parser is happy.

  • Set Module To CommonJS — In the tsconfig that builds Node-run files, set compilerOptions.module to CommonJS.
  • Run The Built Output — Run node on the compiled .js in a build folder, not on the .ts source.
  • Keep Extensions Consistent — If you must mix styles, use .cjs for CommonJS entry files that Node runs.
{
  "compilerOptions": {
    "module": "CommonJS",
    "target": "ES2022",
    "outDir": "./dist-node"
  },
  "include": ["tools/**/*.ts", "server/**/*.ts"]
}

Option B Move Node Code To ESM

This path is a good fit when your Node side already uses imports and you want Node to execute them without flipping back to require. You still might compile TypeScript, but you keep ESM output and align Node’s module detection rules.

  • Mark The Package As ESM — Add "type": "module" in the closest package.json that governs the files Node runs.
  • Use Node-Aware TS Options — Use module modes like nodenext (or newer Node-targeted modes in recent TypeScript) with matching resolution.
  • Use .mjs For Plain JS — If you have raw JavaScript entry points, .mjs removes guesswork.
{
  "type": "module",
  "scripts": {
    "server": "node dist-node/server.js"
  }
}

TypeScript’s Node-focused module options follow Node’s rules that depend on file extensions and the closest package.json type. That’s why changing only tsconfig or only package.json can leave you stuck.

Watch For Monorepo And Workspace Surprises

In workspaces, tools can run inside a package that inherits a different module type than you expect. A nested package.json with "type": "module" can flip how Node treats a plain .js file. When the stack trace points inside a package folder, check the closest package.json, not only the root.

Fixes For Tests And Tooling

When this error shows up in tests, the fix is still module alignment. The difference is where you express it. In Jest, you fix it with transformers and module handling. In ts-node, you fix it with loader mode and a matching tsconfig.

Fixing Import Statement Outside A Module In Jest In Angular Tests

If Jest throws the message on the first import in a test file, your test files are not being transformed into runnable code. If it throws inside a dependency, Jest is skipping transforms for that dependency. Both cases are common in Angular + Jest setups.

  • Use A Preset That Handles Angularjest-preset-angular is a common baseline because it wires up Angular template transforms.
  • Transform .mjs When Needed — Some Angular-era dependencies ship .mjs builds; your Jest transform pattern should include them.
  • Allow Transforms For ESM Dependencies — Adjust transformIgnorePatterns to let Jest transform the specific ESM packages that fail.
module.exports = {
  preset: 'jest-preset-angular',
  transform: {
    '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular'
  },
  transformIgnorePatterns: [
    'node_modules/(?!(@angular|rxjs|your-esm-dep)/)'
  ],
  moduleFileExtensions: ['ts', 'js', 'mjs', 'html', 'json']
};

Be careful with the nuclear option of transforming all of node_modules. It can work, but it can slow test runs a lot. A targeted allow-list is a better trade when only one or two packages ship ESM that Jest can’t parse in your current setup.

When ts-node Or A Dev Script Fails

ts-node is a fast way to run scripts, and it also makes module mismatches show up fast. If you want ESM, run ts-node in ESM mode and use a tsconfig that matches Node’s ESM detection rules. If you want CommonJS, build first and run the output under Node.

  • Use The ESM Loader When Needed — Run ts-node with its ESM loader when your scripts rely on ESM semantics.
  • Split tsconfig Files — Use a script tsconfig for Node code, and keep app build tsconfig for browser builds.
  • Stop Running Production Scripts From Source — For CI, build scripts to a folder and run the emitted JS.

When This Starts After A Package Update

A package can switch its published entry from CommonJS to ESM, and your runner might not be ready for it. That shows up as this exact error, often with a stack trace into node_modules. When that happens, confirm whether the failing dependency now ships ESM as its main path, then adjust transforms or pin the package version until your tooling matches it.

Confirm The Fix And Keep It Stable

After each change, rerun the same command that failed. That keeps the feedback loop tight and stops you from stacking unrelated edits.

Simple Checks That Catch Most Mistakes

  • Print Node Version — Run node -v locally and in CI, since older CI images can lag behind your machine.
  • Inspect The Executed Output — Open the file Node executed and confirm it matches your chosen mode, either require calls or import lines.
  • Check The Closest package.json — Make sure the executed file is governed by the intended "type" setting.

Reusable Checklist For This Exact Error

  • Identify The First Failing File — Use the first non-internal stack line that contains the import token.
  • Choose ESM Or CommonJS For Node — Pick one for scripts, SSR, and tests, then align configs to it.
  • Align tsconfig With The Runner — Make sure TypeScript emits the module format your runner expects.
  • Handle ESM Dependencies In Jest — Allow transforms for the specific ESM packages that break.
  • Retest After Dependency Changes — If a new version flips module format, update transforms or pin.

If you still see this message, search the stack trace for the first file that literally contains the word import. That is the file being parsed under the wrong rules. Fix that one layer and the rest clears.

If you need a sanity check, search your repo for the phrase angular syntaxerror cannot use import statement outside a module in logs. Then verify the fix matches the same runner that produced that log line.

The phrase angular syntaxerror cannot use import statement outside a module looks like one bug, but it’s a module handshake problem. Once the handshake is consistent, Angular code goes back to behaving like Angular code.

Please use a real email you check. If it's fake or mistyped, your message won't reach us and we can't reply — wrong addresses are rejected automatically.