0 / 91
Week 5 · Day 29 of 91

npm and package.json

TypeScript, Packages, and Tooling

Objective

Understand dependencies, scripts, and project metadata before installing libraries.

TypeScript is similar to design-rule checking: it catches invalid connections before runtime but cannot prove system behavior.

  • package.json
  • dependencies versus devDependencies
  • npm scripts and lockfiles

Why this matters

Until now every line of code in this course was yours. From today you start using code other people wrote, and that means answering three questions honestly: what did I pull in, why is it here, and what exactly will land on a teammate's machine when they run one command? By the end of the hour you will have created a package, added a real tool to it, run it through a named script, and removed it again — and you will be able to explain every line of the file that describes it.

What npm actually is

npm is two things sharing a name, which is the source of most early confusion.

  1. The registry — a huge public archive of published JavaScript code at npmjs.com. Each published unit is a package: someone else's code plus a file describing it.
  2. The command-line tool — the npm command, installed alongside Node.js on Day 2, that downloads packages from that registry into your project and keeps a record of what it did.

A dependency is a package your project needs in order to work. Nothing is magic here: npm install downloads files into a folder called node_modules inside your project and writes down what it downloaded.

npm --version
11.13.0

package.json — the file that describes your project

package.json is a plain JSON file in the root of your project. It is the project's description of itself: its name, what it depends on, and the commands you run on it. Nearly every JavaScript tool you will ever use reads it.

Create one with npm init -y (-y means "accept every default without asking"):

{
  "name": "pkg-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "type": "commonjs"
}

Field by field:

  • name and version — the package's identity. npm init -y takes the name from the folder. version follows semantic versioning ("semver"): MAJOR.MINOR.PATCH, where a patch bump is a fix, a minor bump adds something backwards-compatible, and a major bump may break code that used the old version.
  • description, keywords, author, license — metadata for humans and for the registry. Harmless to leave empty on a private project.
  • main — which file is loaded when someone imports your package. Only matters if you publish.
  • type"module" means your .js files use the import/export syntax you learned on Day 23; "commonjs" means the older require() style. It is a real behavioural switch, not metadata.
  • scripts — named commands. More on these below.
  • dependencies / devDependencies — what you installed. Absent until you install something.

`package.json` is the bill of materials

A BOM lists every part a board needs: designator, part number, quantity. It is not the board — it is the document that lets someone else build the same board. package.json is that document for your project. Delete node_modules and the parts are gone; keep package.json and anyone can order them again.

Dependencies versus devDependencies

Two lists, one real distinction: is this package needed by the shipped program, or only by you while you work on it?

  • dependencies — needed at runtime. A date-formatting library your app calls while running belongs here. Install with npm install <name>.
  • devDependencies — needed only during development. Formatters, type checkers, test runners, build tools. Install with npm install --save-dev <name> (short form: -D).

Both install identically on your machine. The difference matters when the code is deployed: a production install can skip devDependencies, and a reader of your package.json can see at a glance what is a shipping part and what is bench equipment.

Parts on the board vs. instruments on the bench

dependencies are the components soldered to the board — remove one and the product stops working. devDependencies are the oscilloscope and the reflow oven: essential to building the board, and not shipped inside the enclosure. Putting your scope in the BOM is not a crime, but it tells the next engineer something false about the product.

npm scripts

The scripts field maps a short name to a shell command. You run one with npm run <name>.

"scripts": {
  "format": "prettier --write .",
  "check-format": "prettier --check ."
}

Two things make scripts worth using over typing the command yourself. First, they are documented and shared — a new person runs npm run build without knowing what tool you chose. Second, npm temporarily puts your project's node_modules/.bin on the command search path, so a script can call a locally installed tool by bare name. That is why prettier --write . works inside a script even though prettier is not installed system-wide.

npm run with no name lists what is available:

Scripts available in [email protected] via `npm run`:
  dev
    vite
  build
    tsc && vite build
  preview
    vite preview

Lockfiles

When you write "prettier": "^3.9.6" in package.json, the ^ is a range, not a version. It means "3.9.6 or any later 3.x release". Install a month later and you may get 3.10.1. That is useful for picking up fixes and terrible for reproducibility.

The lockfilepackage-lock.json, written automatically by npm — closes that gap. It records the exact resolved version of every package that was actually installed, including the dependencies of your dependencies, plus the URL it came from and an integrity checksum:

"node_modules/prettier": {
  "version": "3.9.6",
  "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz",
  "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==",
  "dev": true
}

That is the lockfile's whole job: resolved dependency versions. It holds no passwords, no settings, no source code. Commit it to Git — it is what makes "works on my machine" reproducible. npm ci installs strictly from it, which is what build servers use.

The recipe and the shopping receipt

package.json says "flour". The lockfile is the receipt showing you bought a specific 1kg bag of a specific brand on a specific day. Hand someone the recipe and they may bake something slightly different; hand them the receipt too and they can reproduce your loaf exactly.

Walkthrough

Work in a disposable folder — this one gets deleted at the end.

cd ~/fullstack-journey
mkdir pkg-demo
cd pkg-demo
npm init -y

npm prints the file it wrote. Now add one harmless development dependency. Prettier is a code formatter: it rewrites your files to a consistent style and changes nothing about behaviour.

npm install --save-dev prettier
added 1 package, and audited 2 packages in 2s

found 0 vulnerabilities

Three things changed on disk. Check each:

ls -A
node_modules  package-lock.json  package.json

package.json gained a devDependencies block containing "prettier": "^3.9.6". package-lock.json appeared with the exact version. node_modules holds the downloaded code. Confirm what npm thinks is installed:

npm ls
[email protected] /Users/you/fullstack-journey/pkg-demo
`-- [email protected]

Now make a deliberately messy file and add a script that checks formatting. Edit package.json so scripts contains "check-format": "prettier --check .", then:

printf 'const   a =    1\nconsole.log( a )\n' > demo.js
npm run check-format
Checking formatting...
[warn] demo.js
[warn] Code style issues found in the above file. Run Prettier with --write to fix.

Remember exit codes from Day 4 — this run exits non-zero because it found a problem. Fix it with npx prettier --write demo.js, then re-run the script and watch it pass. Finally, remove the dependency:

npm uninstall prettier
cat package.json

The devDependencies block is gone, and the lockfile has been rewritten to match.

Checkpoint

Say out loud which of the three changed things you would commit to Git (package.json and package-lock.json) and which you would not (node_modules, because it is rebuildable from the other two — and enormous).

How to use AI today

Today's mode is tutor. A tutor-style request asks the AI to explain the concept, give a small example, and then let you attempt it yourself. A request for the finished answer produces a file you cannot defend. Ask for the first kind.

Tutor mode, once your `package.json` exists

"Explain every field in this package.json. Separate standard fields from tool-specific fields." Then close the answer and re-explain three fields from memory before moving on.

Your turn

  1. Make a fresh folder ~/fullstack-journey/pkg-demo and run npm init -y. Read the whole printed file before doing anything else.

  2. Open package.json in VS Code. Write a one-line comment for yourself in a separate notes file for each field, in your own words.

  3. Install Prettier as a development dependency: npm install --save-dev prettier.

  4. Confirm all three effects: devDependencies in package.json, a package-lock.json naming version 3.x.y, and a node_modules folder. Confirm with npm ls.

  5. Add two scripts, format and check-format, as shown above. Run npm run with no arguments and check both appear.

  6. Create a badly formatted .js file, run npm run check-format (it should fail), run npm run format, then run the check again (it should pass).

  7. Run npm uninstall prettier. Confirm devDependencies is gone from package.json.

  8. Run npm run nope and read the error, which names the exact fix:

    npm error Missing script: "nope"
    npm error To see a list of scripts, run:
    npm error   npm run
    

You are done when

You can point at every line of your package.json and say what it does, and say what the lockfile records that package.json does not.

Common pitfalls

  • Committing node_modules. It is thousands of files and fully rebuildable. Add node_modules to .gitignore; commit package.json and package-lock.json.
  • Deleting package-lock.json "to fix things". You throw away the exact versions that worked. If you must reinstall, delete node_modules and run npm ci, which reinstalls from the lockfile.
  • Assuming ^3.9.6 means "3.9.6". It is a range. Only the lockfile pins the real version.
  • Installing globally by reflex. npm install -g puts a tool on your whole machine and outside your project's record. Prefer a devDependency so the project describes its own needs.

Verify it yourself

Open today's reference, the npm Docs page About npm, and follow it to the pages on package.json and on npm install.

  1. This lesson listed nine package.json fields. Find one the docs describe that today's lesson did not mention, and write down what it does.
  2. Find the docs' own statement about which files belong in source control. Does it agree with the pitfall above about node_modules?

Record both answers in ~/fullstack-journey/notes/day-29.md, then delete the pkg-demo folder.

The hour

  1. 0–5 min Recall

    Without notes, state yesterday’s main idea and one unresolved question.

  2. 5–20 min Learn

    Read only the listed concept notes and official reference sections needed today.

  3. 20–48 min Build

    Create a fresh package, inspect package.json, add one harmless development dependency, and remove it again.

  4. 48–55 min Explain and verify

    Run the result, inspect evidence, and explain the data/control flow in your own words.

  5. 55–60 min Quiz and commit

    Complete the quiz, record one lesson, and commit the verified change when applicable.

What to hand in

Deliverable

A package.json whose scripts and dependencies you can explain.

Working with AI today

AI as tutor

Ask for explanations, analogies, questions, and hints. Do not request a complete finished solution first.

Explain every field in this package.json. Separate standard fields from tool-specific fields.

References

End-of-day quiz

Q1 What does a lockfile primarily record?
Q2 Which result best proves today’s work is complete?
Q3 What is the best tutor-style AI request?

Explain-back gate

Pass the quiz above to unlock completion.

Quiz + explain-back checks required.