Understanding package.json and npm
package.json is the manifest npm and the platform read to know how to install and start your application. A sloppy file produces deployments that work on your machine and fail elsewhere. The genuinely useful fields are few, but each has a concrete effect.
The fields that matter
{
"name": "my-app",
"version": "1.4.0",
"private": true,
"main": "index.js",
"scripts": {
"start": "node index.js",
"build": "node build.js"
},
"engines": {
"node": ">=20 <25"
},
"dependencies": {
"express": "^5.1.0"
},
"devDependencies": {
"eslint": "^9.0.0"
}
}nameandversionidentify the project;private: trueprevents accidental publication to the npm registry.mainpoints to the entry file; it must match the real file.scriptsholds named commands, run withnpm run nameornpm start.enginesdocuments the expected Node.js version; it is advisory unlessengine-strictis enabled.dependencieslists what is needed at runtime.devDependencieslists development tools, absent in production.
Dependencies and versions
npm install express adds the library to dependencies and updates the lockfile. Version symbols control which updates are accepted:
| Notation | Accepts | Use |
|---|---|---|
^5.1.0 |
patches and minor 5.x |
default, common trade-off |
~5.1.0 |
patches 5.1.x |
slower evolution |
5.1.0 |
that exact version | critical dependency |
A dependency used only at build or test time goes in devDependencies (npm install --save-dev). If it is required at startup, it goes in dependencies: otherwise it will be missing in production.
Scripts and start command
npm start
npm run build
npm runnpm start runs the start script, or node server.js by default when the script is absent. The platform may also run node index.js directly: the script and the main file must therefore point to the same entry point.
The lockfile
npm install resolves version ranges and writes package-lock.json, which freezes the full dependency tree. Commit that file: without it, two installs can produce different versions.
| Command | Effect | When to use |
|---|---|---|
npm install |
updates package.json and the lockfile, may change versions |
development, adding a dependency |
npm ci |
removes node_modules, installs exactly the lockfile |
deployment, continuous integration |
npm ci fails when package.json and the lockfile are out of sync: that is a safeguard, not a bug. Fix the lockfile with npm install locally, then run it again.
Common errors
- A module works locally because it is installed globally: declare it in
dependencies. npm cifails withoutpackage-lock.json: commit the file.- A native module built on macOS does not run on Linux: reinstall it on the platform.
- A build dependency is missing in production because it sits in
devDependencies. enginesis not enforced: check the version selected in the panel and stay within a supported range.
A readable package.json and a committed lockfile are enough to make a Node.js deployment reproducible.
Advertisement
Was this article helpful?
Read next
- Configure Node.js environment variablesRead, validate and define variables in the panel, without ever putting a secret in the Git repository.
- Configure the Node.js main fileSet the entry point the platform runs and fix path errors.
- Create a Node.js server for app hostingA minimal HTTP server, a correct package.json and a port read from the environment to start on the first try.