Open this lesson in your favourite AI. It'll walk you through the why, explain the demo, and quiz you on the try-it list.
package.json is the manifest, the script runner, the dep contract, the type declaration, the entry-point declaration, and the version pin all in one file. A real project's package.json has 30+ fields and skipping any of them ('main', 'type', 'exports', 'engines', 'scripts') causes a real bug eventually. Knowing every field that matters in 2026 is the difference between 'I copy from a template' and 'I can audit any npm package in 30 seconds'.
A well-structured package.json for a TypeScript service in 2026 carries more information than just dependencies: it specifies the module type ("type": "module" for native ESM), exports maps for proper resolution, and engine constraints to prevent accidental deployment on the wrong Node version. The scripts section is the team's build contract — how you run tests, how you start in development versus production, and how CI invokes the linter. Reading an unfamiliar package.json cold should tell you the entire operational story of how a service is built and run.
pnpm init. Add "type": "module" and "engines": {"node": ">=22"} immediately.scripts.dev using node --watch --env-file=.env. Now pnpm dev is your hot-reload story (no nodemon needed in modern Node).packageManager to pin pnpm/yarn version. Corepack will refuse mismatches.Use these three in order. Each builds on the one before.
In one paragraph, explain what the 'type' field in package.json controls and why setting it to 'module' is the 2026 default.
Walk me through `exports` field resolution. What's the difference between `main`, `module`, and `exports`? Why is `exports` the only one that should matter today?
I'm shipping a library that should work in Node, browsers, and Bun. What does my `exports` field look like? Cover dual-package hazard, conditional exports, and types-first.
{
"name": "@you/myapp",
"version": "0.1.0",
"description": "An example service",
"type": "module", // <-- ESM by default in 2026
"engines": { "node": ">=22" }, // <-- minimum Node version
"packageManager": "pnpm@9.4.0", // <-- corepack reads this
"scripts": {
"dev": "node --watch --env-file=.env src/server.ts",
"build": "tsup",
"start": "node dist/server.js",
"test": "node --test --import tsx",
"lint": "eslint . && prettier --check ."
},
"exports": {
".": { "types": "./dist/index.d.ts", "default": "./dist/index.js" }
},
"dependencies": {
"fastify": "^4.27.0",
"zod": "^3.23.0"
},
"devDependencies": {
"@types/node": "^22",
"tsx": "^4.10.0",
"typescript": "^5.4.0"
}
}
# install + run:
$ pnpm install
$ pnpm devnode main.js