Your app is mostly other people’s code
A plain Next.js project installs several hundred packages. You chose four of them; the rest arrived as dependencies of dependencies. This is normal, it is how modern software is built, and it is also where a category of failure lives that has nothing to do with your code.
The three files
package.json lists what you asked for, with ranges: "next": "^15.1.0" means 15.1.0 or any later 15.x.
package-lock.json (or pnpm-lock.yaml, or yarn.lock) records exactly which versions were actually installed, all several hundred of them. Commit this file. Without it, your machine and your server can install different versions of the same project and behave differently, which produces the most maddening class of bug in this course.
node_modules is the downloaded result. Never committed, never edited, deletable at any time.
npm install respects the lock file. npm update deliberately ignores it and moves versions forward. Knowing which of those you ran is often the answer to why things changed.
Reading a version number
15.1.3 is major.minor.patch, and the convention says a major bump may break your code deliberately, a minor adds things, a patch fixes things.
The prefix in package.json decides how much movement is allowed. ^15.1.0 accepts any 15.x. ~15.1.0 accepts 15.1.x only. 15.1.0 with no prefix accepts exactly that.
The convention is widely followed and not guaranteed. Plenty of minor releases have broken something for somebody. This is why the lock file exists.
The failures and what they actually mean
Module not found after pulling somebody’s changes. They added a dependency; you have not installed it. npm install.
Two versions of the same library. Two packages each depend on a different version of a third. Symptoms are strange rather than obviously wrong: a React app where hooks throw about invalid calls is the classic. npm ls <package> shows you the tree.
Peer dependency warnings. A package wants a version of something else that you do not have. Sometimes fine, sometimes the actual cause of your problem. Do not reflexively reach for --force or --legacy-peer-deps; they silence the complaint and keep the mismatch.
It broke and I changed nothing. An unpinned range let a new version in on a fresh install. This is exactly what the lock file prevents, which is why deleting it to fix a problem is nearly always the wrong move.
The reinstall ritual
rm -rf node_modules package-lock.json
npm installThis fixes corrupted installs. It also throws away your record of known-good versions and installs whatever is newest within your ranges, which can introduce a different problem than the one you had.
So try the smaller version first: rm -rf node_modules && npm ci. npm ci installs exactly what the lock file says, nothing newer. If that fixes it, the install was corrupt. If it does not, the lock file was not the problem and deleting it would have taught you nothing while changing several hundred versions.
Every dependency is a decision
An agent asked to add date formatting may install a library rather than write four lines. Each package added is code you did not read, running in your app, with its own dependencies and its own security history.
This is the reason for the standing rule in your rules file: no new dependencies without asking. When one is proposed, three questions are enough. Is it maintained: when was the last release? How many packages does it drag in? Could this be ten lines instead?
Sometimes the answer is clearly yes, install it. Date and time handling, authentication, anything cryptographic: write those yourself and you will get them wrong. The judgement is about whether the problem is hard.
Updating on purpose
npm outdated # what has moved on
npm audit # known vulnerabilities in what you haveUpdate deliberately, one significant package at a time, with a commit before and a check after. Not the day before a launch, and never all at once: a hundred packages updated together means an unexplained failure has a hundred suspects.
npm audit deserves a note of honesty: it over-reports. Many of its warnings are for build-time tooling that never runs in production, or for attack paths that do not exist in your app. Read what the vulnerability actually is rather than chasing the number to zero.
Every lesson here is open. Your progress is recorded once you pass the Building with AI exam.
Check your understanding
An app that worked last week fails on a colleague’s fresh install, with the same code. What is the most likely cause?
Pick the one you would defend. Your answer stays private.
Stuck on something?Ask Beatriz, your AI tutor
