Node.js v22 JSON Import SyntaxError: Unexpected identifier 'assert'
Problem Statement
When migrating from Node.js 21 to Node.js 22, you may encounter the error SyntaxError: Unexpected identifier 'assert'
when attempting to import JSON files using the syntax:
import config from "./some-config-file.json" assert { type: "json" };
This code worked correctly in Node.js 21 but fails in Node.js 22 due to deliberate syntax changes in the ECMAScript specifications. The error appears immediately during module resolution:
SyntaxError: Unexpected identifier 'assert'
at compileSourceTextModule (node:internal/modules/esm/utils:337:16)
at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:166:18)
at callTranslator (node:internal/modules/esm/loader:436:14)
at ModuleLoader.moduleProvider (node:internal/modules/esm/loader:442:30)
at async ModuleJob._link (node:internal/modules/esm/module_job:106:19)
This issue occurs specifically because Node.js 22 removed support for "import assertions" in favor of the newer "import attributes" specification.
Why This Change Occurred
The syntax change results from the evolution of the ECMAScript proposal:
- The original
assert
syntax (import assertions) was supported in Node.js 17.1+ and 16.14+ - The proposal was renamed to "import attributes" with the
with
keyword replacingassert
- Node.js 22 implements the finalized specification, removing
assert
syntax entirely - This change occurred because future import attributes will have functionalities beyond simple assertions
Note
Despite this syntax change, JSON import behavior remains identical - only the keyword has changed.
Recommended Solutions
Solution 1: Use with
Keyword (Node.js 18.20+)
Update your import statement to use the with
keyword instead of assert
:
import config from "./some-config-file.json" with { type: "json" };
Pros:
- Minimal code change
- Maintains static import advantages
- Follows current ECMAScript standards
Cons:
- Only supported in Node.js 18.20 and later
- Breaks compatibility with Node v16 and v17
Solution 2: Cross-Version Compatibility with createRequire
(Recommended)
Use Node's built-in createRequire
to load JSON files in a version-agnostic way:
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
// Works in all Node versions since v12.2.0
const config = require('./some-config-file.json');
Advantages:
- Full backward compatibility (works in Node.js v12.2+)
- Maintains JSON module caching (identical to
import
behavior) - Simple implementation requiring minimal code changes
Solution 3: Manual JSON Parsing
If you need to avoid all module system features, manually read and parse the JSON file:
import fs from 'node:fs/promises';
const config = JSON.parse(
await fs.readFile(
new URL('./some-config-file.json', import.meta.url),
'utf8'
)
);
Use When:
- Direct filesystem access is required
- You need special JSON parsing behavior
- Maintaining Node v12 compatibility (without
createRequire
) - Modifying JSON files during program execution
Performance Note
Manual parsing doesn't cache JSON contents. For frequently accessed files, implement caching or use createRequire
.
Compatibility Table
Solution | Node v12.2+ | Node v16-17 | Node v18.20+ | Node v22+ |
---|---|---|---|---|
assert (original) | ❌ | ✅ | ✅ | ❌ |
with syntax | ❌ | ❌ | ✅ | ✅ |
createRequire method | ✅ | ✅ | ✅ | ✅ |
Manual parsing | ✅ | ✅ | ✅ | ✅ |
Final Recommendation
For most projects, Solution 2 (createRequire
) provides the best balance of:
- Compatibility across Node versions
- Performance with built-in caching
- Code simplicity and maintainability
Migrating to with
syntax (Solution 1) is appropriate if you exclusively support Node.js 18.20+. Reserve Solution 3 for edge cases requiring direct filesystem access or specialized JSON parsing.