Terminal
$ npm run dev
sh: next: command not found
npm error code 127

The code is fine. Nothing is installed yet. Most of the failures in your first week are this category: the project is asking for something your machine does not have, in a folder it is not looking in.

The idea

The code you and your assistant write is a small fraction of what runs. The rest arrives as , downloaded by a such as npm or pnpm. Running the project means installing those, then starting a dev server that compiles your files and serves them to your browser at an address on your own computer.

text
  package.json            "next": "16.0.1", "react": "19.0.0"
        |
        |  npm install   (reads the list, writes the lockfile)
        v
  node_modules/           the downloaded packages. Large, and never committed.
        |
        |  npm run dev
        v
  dev server (a running program, holds your terminal)
        |
        v
  http://localhost:3000   localhost = this machine.  3000 = the port.

How it works

  • package.json lists what the project needs and defines the shortcut commands under scripts, so npm run dev runs whatever that project decided dev means.
  • The lockfile (package-lock.json for npm, pnpm-lock.yaml for pnpm) records the exact version of every package installed. It is committed to git so a second machine gets identical versions. node_modules/ is not committed, because it can be rebuilt from those two files.
  • npm install downloads everything the list asks for. npm install resend adds one new package and updates both files.
  • A keeps running until you stop it with Control+C, and the terminal tab it occupies is busy for as long as it runs.
  • localhost means this computer, and the after the colon says which program to reach. Next.js defaults to 3000, Vite to 5173.

What to do

  1. Install once per project, in the project root: npm install, or pnpm install if the repository has a pnpm-lock.yaml. Mixing the two in one project produces two lockfiles and hours of confusion.
  2. Start it with npm run dev and open the address it prints. Leave that tab alone.
  3. When a build fails, fix the first error and run it again. The errors below the first one are often consequences of it, and they disappear on their own.
  4. Work through the five that catch everyone:
    • command not found, or Cannot find module 'x'. Nothing is installed, or you are in the wrong folder. Run ls and check you can see package.json.
    • Port 3000 is in use, trying 3001 instead. An older dev server is still running. Next.js usually just moves to the next free port, so read the address it prints rather than typing 3000 from memory. To reclaim 3000, press Control+C in the old tab, or run npx kill-port 3000. (npx runs a package once without installing it into your project.)
    • A crash inside node_modules, or npm warning about an unsupported engine. Usually your Node version. Run node -v and compare it against what the project's README or engines field asks for.
    • undefined where a key should be. A missing . Copy .env.example to .env.local and fill it in.
    • Changes that do not appear, or an error that survives its own fix. A stale install or cache. Stop the server, delete node_modules and the framework's build folder (.next for Next.js), and install again.

Where it breaks

Working on your machine proves less than it feels like it proves. Your laptop has your Node version, your .env.local, your cached build and a case-insensitive filesystem, and a server has none of those. This is the real content of "it works on my machine", and it is why section 6 gives environments a section of their own.

The dev server also flatters you. It rebuilds constantly, keeps the code readable instead of compressing it, and shows errors written for you rather than for a stranger, so it is faster and more forgiving than the production build. npm run build is the command that tells you the truth, and it is worth running before you promise anyone anything.