Import built-in Node modules with the 'node:' protocol – why it matters
1. Background
The node: prefix was added to eliminate typosquatting when importing core modules. Developers often mistype module names like 'event' instead of 'events' or 'http2' instead of 'http', accidentally installing malicious packages that mimic official Node.js modules.
2. Syntax shift
- ESM: Change
import { createServer } from 'http'→import { createServer } from 'node:http' - CommonJS: Change
const http = require('http')→const http = require('node:http')
3. Minimal working example
// server.mjs
import { createServer } from 'node:http';
const server = createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from node:http!\n');
});
server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});
Run with: node server.mjs
4. What breaks without the prefix
Node resolves the name as an npm package, so import { createServer } from 'http' will:
- Install a malicious
'http'package if it exists on npm - Lose ESLint/IDE hints that it's a built-in module
- Create confusion between official and third-party modules
5. Security & tooling benefits
- ESLint rule
prefer-node-protocol: Flags missing prefix, encouraging correct imports - Static analyzers: Treat the module as trusted core code rather than external dependency
- Explicit intent: Makes it clear to reviewers and teammates that you're using Node's built-in functionality
- Prevention: Eliminates typosquatting attacks where malicious packages exploit common module name misspellings
6. Adoption checklist
- Run
npm audit: Check for existing vulnerable packages using incorrect imports - Update ESLint config: Add
plugin:node/recommendandplugin:node/no-deprecated - Replace all
require('…')of core modules: Userequire('node:module-name')syntax - Verify tests still pass: Some test mocks might rely on the old import pattern
- Document the change: Update contributing guide and README with new import conventions
Summary
The node: protocol is a security improvement that prevents typosquatting attacks and clarifies intent when using Node's built-in modules. While it's a simple syntax change, it has significant security implications and tooling benefits. Adoption is straightforward but important for maintaining security hygiene in Node.js projects.
:::warning Need to check
Verify the exact version when node: protocol was introduced and confirm ESLint rule availability.
:::
:::warning Need to check Check if there are any edge cases where the old import syntax might still work but could introduce security risks. :::
:::warning Need to check Investigate any migration challenges for large codebases transitioning to the new protocol. :::
References
- Node.js documentation on module resolution
- ESLint plugin configuration examples
- npm security advisories related to typosquatting