What you'll learn
npm makes a Node.js project repeatable: package.json records its contract, the lockfile captures an exact dependency graph, and scripts give every contributor the same commands.
By the end of this lesson, you'll be able to:
- Create and read a package.json file
- Separate production dependencies from development tools
- Interpret semantic-version ranges and preserve the lockfile
- Automate repeatable development tasks with npm scripts
Core mental model
Node.js becomes easier when you separate the JavaScript language from the runtime and the operating-system capabilities it exposes. Use this table as a decision guide.
| Concept | What it means | Decision rule |
|---|---|---|
| package.json | Project metadata, scripts, module mode, and dependency ranges | Commit it as the human-maintained project contract |
| package-lock.json | The exact resolved dependency tree | Commit it for applications so installs are reproducible |
| Semantic version | major.minor.patch communicates compatibility intent | Review major upgrades; test every dependency update |
| npm script | A named project command run in a predictable package context | Give common checks short stable names such as test and start |
Professional workflow
Build and verify Node.js programs from the terminal in small, observable steps.
- Initialize the project and inspect every generated field.
- Declare the supported module format and Node.js engine range.
- Install runtime libraries as dependencies and build/test tools as devDependencies.
- Commit package.json and package-lock.json together.
- Create scripts for start, development, tests, and validation.
- Review package source, maintenance, license, size, and security before adoption.
Keep the feedback loop short
Guided code lab
Initialize and inspect a project
npm init creates the package contract. npm pkg set provides a scriptable way to update common fields.
mkdir node-course-lab
cd node-course-lab
npm init -y
npm pkg set type=module
npm pkg set engines.node=">=22"
npm pkg set scripts.start="node src/app.js"Read the project contract
Scripts describe common operations. Dependencies belong to the running app; devDependencies support development and verification.
{
"name": "node-course-lab",
"version": "1.0.0",
"private": true,
"type": "module",
"engines": { "node": ">=22" },
"scripts": {
"start": "node src/app.js",
"check": "node --check src/app.js",
"test": "node --test"
}
}Install deliberately and run shared scripts
Use a development dependency for tooling. npm ci uses the committed lockfile and is the usual clean-install command in automation.
npm install dotenv
npm install --save-dev eslint
npm run check
npm test
npm ci
npm auditProduction practice
Review packages
A tiny dependency can carry a large transitive graph. Check ownership, release history, license, and whether the feature belongs in your own code.
Keep the lockfile
Commit lockfile changes with dependency changes and review unexpected transitive updates.
Automate checks
CI should use the same npm scripts developers run locally so there is one shared definition of success.
Common failure mode
Independent workshop
Turn your runtime-report program into a documented npm project with predictable setup, start, check, and test commands.
Your finished workshop must include:
- A complete package.json with type and engines
- At least four useful scripts
- One justified runtime or development dependency
- A committed lockfile and setup section in README
Definition of done
Recap & quick check
Key takeaways
- package.json is the project contract
- The lockfile records exact resolutions
- Semantic versions communicate compatibility intent
- Production and development dependencies serve different roles
- npm scripts standardize workflows
Quick check
1. Where should a library required by the running application be listed?
2. What does a major semantic-version change normally signal?
3. Why commit package-lock.json for an application?
4. Which command is designed for a clean lockfile-based install?
Next: Files, Paths & Essential Core APIs