Packages and npm
By Syncfusion®, Inc. · Last updated
What npm and the npm registry are, package.json fields, dependency types, installing and updating packages, semantic versioning and version ranges, package-lock.json and npm ci, npm scripts and node --run, npx and local binaries, how Vite and the Angular CLI use Node.js, npm audit, package entry points with exports and imports, and optional workspaces, publishing and other package managers.
Packages and npm
Package = a folder of code with a package.json file, ready to share.
npm = the tool that downloads, updates and shares packages.
- Other people have already written code for common jobs.
- You can use their packages instead of writing everything yourself.
- npm comes with Node.js. You installed it in Introduction to Node.js.
Simple lesson: a package is shared code, and npm is the tool that moves it around.
A Real-World Example
Think of a school library.
- The library has thousands of books on its shelves.
- A student fills in a borrow slip with the book name and edition.
- The librarian fetches the book from the shelf.
- The register keeps the exact copy number, so the same copy can be found again.
Now the mapping:
- The shelves are the npm registry.
- The borrow slip is package.json.
- The librarian is the npm command.
- The register is package-lock.json.
What You Will Learn
In this lesson, you will learn:
- What npm and the npm registry are
- The main fields of
package.json - Dependency types and installing, updating and removing packages
- Semantic versioning and version ranges
package-lock.json,npm installandnpm ci- npm scripts,
node --run,npxand local tools - How Vite and the Angular CLI use Node.js
- Package safety with
npm audit - Package entry points, and optional extras: workspaces, publishing, pnpm and Yarn
npm Fundamentals
- npm registry = a huge online store of free packages at npmjs.com.
- npm (the command) = the program you type in the terminal, such as
npm install. - Node.js runs your code. npm manages the packages your code uses.
- Packages go into a folder called
node_modulesinside your project.
Never edit files inside node_modules. The next npm install replaces them.
Animation: npm reads package.json, downloads a package from the registry into node_modules, and writes package-lock.json
package.json "dayjs": "^1.11.0"
npm install
npm registry
node_modules
npm also writes package-lock.json with the exact versions
package.json says what you want, npm fetches it, and node_modules holds it.
Simple lesson: the registry stores packages, and npm copies them into your project.
package.json in Depth
npm init -y makes a starter package.json.
$ npm init -y
Wrote to /home/asha/school/package.json:
{
"name": "school",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
The main fields:
nameandversion= who the package is and which edition.description,author,license= facts for other people.main= the entry file when someone loads your package.type="module"makes.jsfiles ES modules.scripts= short names for commands, such as"start": "node app.js".engines= which Node.js versions the project needs, such as{ "node": ">=22" }.private: true= blocksnpm publish, so a school project is never published by mistake.files= which files go into the package when you publish it.
Simple lesson: package.json is the ID card and the command list of your project.
Dependencies
Dependency = a package your project needs.
dependencies= needed when the app runs, such asexpress.devDependencies= needed only while you build and test, such astypescript.peerDependencies= a package your package expects the user to install, such as a plugin that needsreact.optionalDependencies= nice to have. Install does not fail without them.
npm install dayjs # add to dependencies
npm install -D typescript # add to devDependencies
npm install dayjs@1.11.10 # an exact version
npm install -g nodemon # global: a tool for every project
npm uninstall dayjs # remove it
- Local install = goes into this project's
node_modules. Use this almost always. - Global install (
-g) = goes into one shared place on your computer. Use it only for command-line tools.
Checking Your Packages
npm ls= show the installed packages as a tree.npm outdated= show packages that have newer versions.npm update= update packages inside the allowed version range.
package.json
{
"name": "school-report",
"version": "1.0.0",
"private": true
}
$ npm ls
school-report@1.0.0 /home/asha/school
`-- (empty)
Simple lesson: app needs go in dependencies, tool needs go in devDependencies.
Versioning
Semantic versioning (SemVer) = a version number in three parts: MAJOR.MINOR.PATCH.
- PATCH (1.4.2 → 1.4.3) = a bug fix. Nothing breaks.
- MINOR (1.4.2 → 1.5.0) = a new feature. Old code still works.
- MAJOR (1.4.2 → 2.0.0) = a breaking change. Old code may stop working.
- Prerelease (
2.0.0-beta.1) = a test version before the real release.
Version Ranges
| Range | Means | Allows |
|---|---|---|
1.4.2 | Exactly this | only 1.4.2 |
^1.4.2 | Same major | 1.4.2 up to below 2.0.0 |
~1.4.2 | Same minor | 1.4.2 up to below 1.5.0 |
>=1.4.2 | This or newer | anything from 1.4.2 |
* | Any version | everything (risky) |
npm install writes ^ by default. You get fixes and features, but no breaking changes.
Commit package-lock.json to Git. It makes every install on every computer the same.
This is a small copy of what npm does. The real rules also handle 0.x versions and prereleases.
Simple lesson: read a version as major.minor.patch, and ^ never jumps to a new major.
Which versions ^1.4.2 and ~1.4.2 accept Version 1.4.2 = MAJOR . MINOR . PATCH 1.4.2 1.4.9 1.7.0 2.0.0 ^1.4.2accepts 1.4.2, 1.4.9 and 1.7.0. Never 2.0.0. ~1.4.2accepts 1.4.2 and 1.4.9 only. A new MAJOR number means breaking changes, so npm never jumps to it on its own.
^ allows new minor and patch versions. ~ allows only new patch versions.
Lockfiles
package-lock.json = the exact version of every installed package, including packages of packages.
package.jsonsays^1.11.0. That is a range.package-lock.jsonsays1.11.13. That is the exact copy.- Commit the lockfile to Git. Then everyone installs the same versions.
npm install vs npm ci:
npm install= install and update the lockfile when needed. Use it while you work.npm ci= deletenode_modulesand install exactly what the lockfile says. It fails if the lockfile does not matchpackage.json. Use it on build servers.
Simple lesson: package.json allows a range, the lockfile pins one exact version.
npm Scripts
npm script = a named command in the "scripts" part of package.json.
npm run reportruns the"report"script.npm startandnpm testare short forms for two common names.- Words after
--are passed to the script:npm run greet -- Asha. - npm adds
node_modules/.binto the path, so installed tools run by name. - npm sets variables such as
npm_package_namefor the script. node --run reportruns a script faster, without npm's extra work.
Click ▶ Run. The lab runs npm run greet -- Meena.
- The banner: npm prints the package name, version and script name first.
- The argument:
Meenaarrived inprocess.argv[2], because it came after--. - The variable:
npm_package_namewas filled in by npm.
Lifecycle Scripts: pre and post
- A script named
prebuildruns beforebuild. A script namedpostbuildruns after it. npm installruns a package'sinstallandpostinstallscripts. This is why you should trust a package before installing it.
package.json
{
"name": "school-report",
"version": "1.0.0",
"scripts": {
"prebuild": "echo 1. cleaning old files",
"build": "echo 2. building the report",
"postbuild": "echo 3. done"
}
}
$ npm run build
> school-report@1.0.0 prebuild
> echo 1. cleaning old files
1. cleaning old files
> school-report@1.0.0 build
> echo 2. building the report
2. building the report
> school-report@1.0.0 postbuild
> echo 3. done
3. done
Environment Variables in Scripts
"start": "NODE_ENV=production node app.js"sets a variable for one command.- That form works on Mac and Linux. On Windows Command Prompt it does not.
- For all systems, use
node --env-file=.env app.js, or thecross-envpackage.
Simple lesson: scripts give long commands short names, and -- passes your own words to them.
Running Packages: npx and Local Tools
- Installed tools put their commands in
node_modules/.bin. npx <tool>= run a tool fromnode_modules/.bin. If it is missing, npx offers to download it and run it once.- Example:
npx tsc --versionruns the TypeScript compiler of this project. - Corepack = a helper that sets up pnpm or Yarn. It came with older Node.js versions. Newer versions need
npm install -g corepack.
How Vite and the Angular CLI Use Node.js
The React, Vue and Angular courses start with commands like npm run dev. Here is what happens.
npm create vite@latestdownloads the Vite starter package and runs it with Node.js.npm run devruns the"dev"script, which starts Vite, a Node.js program.- Vite reads your files with
fs, builds them and serves them onlocalhostwithhttp. ng servein Angular works the same way: the Angular CLI is a Node.js program.- In browser code, Vite gives you
import.meta.env. In Node.js code, you useprocess.env.
Simple lesson: frontend tools are Node.js programs, and npm scripts start them.
Package Safety
A package runs on your computer with your rights. Check it first.
npm audit= checks your installed packages against a list of known security problems.npm audit fix= updates packages to fixed versions, inside your version ranges.- Before installing, check the weekly downloads, the last update date and the GitHub page.
- Watch for look-alike names, such as
expresinstead ofexpress. This trick is called typosquatting. - Read
postinstallscripts of small, unknown packages. They run during install.
$ npm audit
# npm audit report
minimist <1.2.6
Severity: critical
Prototype Pollution in minimist
fix available via `npm audit fix`
1 critical severity vulnerability
This output is an example. Your report depends on your packages.
npm audit fix --force may install breaking major versions. Read what it changes, and run your tests after.
Simple lesson: treat a new package like a stranger's USB stick. Check it before you plug it in.
Package Entry Points (Advanced)
exports field = the list of files other people may import from your package.
- Without
exports, anyone can import any file inside the package. - With
exports, only the listed paths work. Others getERR_PACKAGE_PATH_NOT_EXPORTED. - Conditional exports = give
importusers one file andrequireusers another. - Subpath imports (
#) = short private names inside your own package, set in"imports".
"."withimportandrequire: this is a dual package. It serves both module systems."./grades": a public subpath.secret.js: the file exists, butexportsdoes not list it, so Node.js blocks it.
Simple lesson: exports is the front gate of your package. Only listed paths get in.
Workspaces (Optional)
Workspaces = several packages in one repository, managed by one npm install.
- Add
"workspaces": ["packages/*"]to the rootpackage.json. - Shared dependencies are installed once, in the root
node_modules. npm run test --workspacesrunstestin every package.npm run build -w packages/reportsruns it in one package.
Publishing (Optional)
- Remove
"private": trueand pick a uniquename. - List the files to share in
"files". - Run
npm pack --dry-runto see what would be uploaded. - Run
npm version patchto raise the version number. - Run
npm publish(afternpm login).
package.json
{
"name": "@greenfield/grades",
"version": "1.0.0",
"main": "index.js",
"files": ["index.js"]
}
index.js
module.exports.grade = (m) => (m >= 90 ? "A" : "B");
notes.txt
These notes stay private.
$ npm pack --dry-run
npm notice Tarball Contents
npm notice 53B index.js
npm notice 104B package.json
npm notice total files: 2
notes.txtis not in the list, because"files"only allowsindex.js.- Scoped package = a name like
@greenfield/grades. The scope groups a team's packages. npm deprecate <name>@<version> "message"warns people away from an old version.
Other Package Managers (Optional)
- pnpm = saves disk space by storing each package version once and linking it. Fast installs.
- Yarn = another package manager with its own lockfile,
yarn.lock. - Both read the same
package.json. Use the one your team already uses. - Do not mix them in one project. Each writes its own lockfile.
Common mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
Not committing package-lock.json | The lockfile is temporary | Commit it | Teammates get different versions |
Editing files in node_modules | It is my code now | Change your own code, or fork the package | The next install wipes your change |
Putting typescript in dependencies | All packages are the same | Build tools go in devDependencies | Production installs carry extra weight |
npm run greet Asha | npm passes words to the script | Use npm run greet -- Asha | npm may treat the word as its own option |
Installing project tools with -g | Global is easier | Install locally and use npx | Different projects need different versions |
| Installing a package with a look-alike name | Names are checked by npm | Check the exact name and its downloads | A harmful package may run on install |
Using npm install on a build server | Both commands are the same | Use npm ci | Builds may get different versions |
TL;DR
- npm = the package tool. Registry = the online store of packages.
- package.json = name, version, type, scripts, engines and dependencies.
- dependencies = needed to run. devDependencies = needed to build and test.
SemVer = MAJOR.MINOR.PATCH.
^same major,~same minor
- package-lock.json = exact versions. Commit it. Use
npm cion servers. - npm scripts = named commands.
--passes your own arguments. - npx = run a tool from
node_modules/.bin. - npm audit = check packages for known security problems.
- exports = the list of paths a package allows.
Check Yourself
Exercises
What to Remember
- npm downloads packages from the registry into
node_modules. package.jsonlists what you need.package-lock.jsonpins exact versions.^allows new minor and patch versions, never a new major.- Use
npm cion servers, andnpm run name -- wordsto pass arguments. - Check a package before installing it, and run
npm audit. exportsdecides which files of a package others may import.
Next: Event Loop and Timers. You will see how Node.js keeps working while slow jobs finish.