The jsconfig.json, the package.json scripts and the two files at the end of this page are one real project, checked with TypeScript 5.9 every time this site is built.
Install
TypeScript is a development dependency: it checks your code and never runs in production. @types/node gives the checker the types of Node's built-in modules (node:fs, node:http, process and the rest). Pick the @types/node major version that matches the Node.js you run, for example @types/node@24 for Node.js 24.
npm install --save-dev typescript @types/node jsconfig.json
nodenext makes TypeScript resolve imports the way Node.js does: a relative import needs its file extension (./config.js, not ./config), and a package's exports field decides what you can import from it. target: "es2024" matches the JavaScript that current Node.js releases run.
types: ["node"] loads only Node's types as globals, so an unrelated @types package somewhere in node_modules cannot add globals you never use. skipLibCheck skips checking the .d.ts files of your dependencies, which saves time and avoids errors you cannot fix; your own files are still checked in full.
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"module": "nodenext",
"moduleResolution": "nodenext",
"target": "es2024",
"types": ["node"],
"skipLibCheck": true
},
"include": ["src/**/*.js"]
} npm scripts
lint checks the whole project once, which is what CI should run. lint:watch keeps tsc running and checks again on every save; --preserveWatchOutput keeps the earlier output on screen instead of clearing it.
{
"type": "module",
"scripts": {
"lint": "tsc -p jsconfig.json",
"lint:watch": "tsc -p jsconfig.json --watch --preserveWatchOutput"
}
} What nodenext checks in your imports
With this config, the checker holds your imports to Node's rules:
- relative imports carry their extension:
import { loadConfig } from "./config.js"; leaving it off is TS2835, shown below - built-in modules work with or without the
node:prefix; the prefix makes it obvious which imports are built in - top-level
awaitis allowed, because ES modules allow it (the example'smain.jsuses it)
import { formatPrice } from "./format";error TS2835: Relative import paths need explicit file extensions in ECMAScript imports when '--moduleResolution' is 'node16' or 'nodenext'. Did you mean './format.js'?
console.log(formatPrice(1999));jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"module": "nodenext",
"moduleResolution": "nodenext",
"target": "es2024",
"types": ["node"],
"skipLibCheck": true
},
"include": ["*.js"]
} The example project
A two-file server: src/config.js reads and types a JSON config file, and src/main.js imports it and starts an HTTP server. Both files are checked with the jsconfig.json above.
import { readFile } from "node:fs/promises";
/**
* @typedef {object} Config
* @property {number} port
* @property {string} [host]
*/
/**
* @param {URL} file
* @returns {Promise<Config>}
*/
export async function loadConfig(file) {
const text = await readFile(file, "utf8");
/** @type {Config} */
const config = JSON.parse(text);
return { host: "localhost", ...config };
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"module": "nodenext",
"moduleResolution": "nodenext",
"target": "es2024",
"types": ["node"],
"skipLibCheck": true
},
"include": ["src/**/*.js"]
} import { createServer } from "node:http";
import { loadConfig } from "./config.js";
const config = await loadConfig(new URL("../config.json", import.meta.url));
createServer((req, res) => {
res.end(`You asked for ${req.url}`);
}).listen(config.port, config.host);jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"module": "nodenext",
"moduleResolution": "nodenext",
"target": "es2024",
"types": ["node"],
"skipLibCheck": true
},
"include": ["src/**/*.js"]
} In your editor
VS Code reads this jsconfig.json with no further setup. To make it use the same TypeScript as npm run lint, see VS Code.
Sources
- Modules: Packages, "type" · Node.js docs
- Modules: ECMAScript modules · Node.js docs
- Modules: Reference · TypeScript handbook
- @types/node · npm
Last reviewed 20 October 2026.