Lesson 31 · Module 5.2 — Tooling & ecosystem

Reading a tsconfig: module vs moduleResolution

Two tsconfig options sound like synonyms and constantly get confused: module and moduleResolution. They answer different questions. One controls the import/export syntax TS writes out; the other controls how TS locates a file you import. Separate those two questions and the whole config stops being a guessing game.

The one rule

module = what module syntax TypeScript emits (ESM import/export, or CommonJS require). moduleResolution = how TypeScript finds the file behind an import (which folders and extensions it searches, and whether it reads package.json). Emit vs find. They are set independently.

The two questions, side by side

optionquestion it answersexample values
modulewhat does the output import/export syntax look like?esnext, commonjs, nodenext
moduleResolutionhow is "./x" or "lodash" resolved to a file?bundler, node16, nodenext

module shapes the JavaScript that comes out. moduleResolution shapes the lookup that happens during checking — it never appears in the output, only decides which file a specifier points at. A modern setup usually picks a matched pair (e.g. both nodenext) so emit and resolution agree.

A small tsconfig, decoded

{
  "compilerOptions": {
    "module": "nodenext",            // EMIT: ESM or CJS, picked per package.json "type"
    "moduleResolution": "nodenext",  // FIND: use Node's rules — read "exports", check extensions
    "target": "es2022"             // (separate concern: which JS features to down-level)
  }
}

Read it as two sentences: "emit module code the way modern Node expects" and "resolve imports the way modern Node does." The values happen to share a name here, but they are answering the two different questions from the rule above.

Where package.json joins in

TypeScript does not decide everything alone — it reads two fields from package.json:

So three things cooperate: module (emit), moduleResolution (find), and package.json (the package's own declared rules that both consult).

Check yourself

Recall, don’t re-read. (Answers reveal on click.)

What does the module compiler option actually control?
When TypeScript turns import x from "lodash" into a real file path, that is governed by…
Under nodenext, what does a package's "type": "module" field do?

Primary source

The canonical references are the tsconfig reference — module and moduleResolution, plus the handbook's Modules — Theory and Modules — Reference (package.json type & exports). Best way to feel it: flip module between commonjs and esnext in the TS Playground and watch the emitted require turn into import.

Try it yourself

Got a "cannot find module" or a surprising require in your output? Paste the tsconfig snippet and ask “is this an emit problem (module) or a find problem (moduleResolution)?” Next lesson (5.3) closes the course — where TypeScript itself is headed.