/commands/yarn/yarn-add-dev-dependency
yarn add --dev: add a devDependency with Yarn (classic and Berry)
- tool
- Yarn
- versions
- Yarn 1.x, Yarn 2+, Yarn 4
- os
- any
yarn add --dev typescript (short form yarn add -D typescript) installs a package and records it under devDependencies in package.json, for tools you need while developing and testing but not at run time: test runners, linters, compilers, type definitions. The flag is the same in Yarn 1 (classic) and Yarn 2+ (Berry); what differs is how each one saves the version and lays out the install.
Yarn 1 (classic)
echo '{ "name": "app", "version": "1.0.0", "license": "MIT", "private": true }' > package.json
npx --yes yarn@1 add --dev --silent --no-progress is-number@6.0.0
cat package.json
ls -d node_modules/is-number yarn.lockOutput
{
"name": "app",
"version": "1.0.0",
"license": "MIT",
"private": true,
"devDependencies": {
"is-number": "6.0.0"
}
}
node_modules/is-number
yarn.lockYarn 1 saves the specifier you typed (here the exact 6.0.0; without a version it writes a caret range such as ^7.0.0), installs into node_modules and writes yarn.lock. The example runs Yarn through npx yarn@1; with Yarn installed the command is yarn add --dev is-number@6.0.0.
Yarn 4 (Berry)
echo '{ "name": "app", "version": "1.0.0", "license": "MIT", "private": true }' > package.json
touch yarn.lock
npx --yes @yarnpkg/cli-dist@4 add -D is-number@6.0.0 > /dev/null
cat package.json
ls -a | grep -E "^(\.pnp\.cjs|\.yarn|yarn\.lock)$"Output
{
"name": "app",
"version": "1.0.0",
"license": "MIT",
"private": true,
"devDependencies": {
"is-number": "6.0.0"
}
}
.pnp.cjs
.yarn
yarn.lockThe empty yarn.lock marks the folder as its own Yarn project. Yarn 4 saves the same entry, but by default uses Plug'n'Play: instead of node_modules it writes .pnp.cjs and keeps packages as zip files in a cache. Set nodeLinker: node-modules in .yarnrc.yml if your tools need a classic node_modules folder.
Options
| Command | What it does |
|---|---|
| yarn add -D jest | devDependencies (same in Yarn 1 and 2+) |
| yarn add -D -E prettier | Save the exact version instead of a caret range (--exact) |
| yarn add -D -T eslint | Save a tilde range, patch updates only (--tilde) |
| yarn add -P react | peerDependencies (--peer) |
| yarn add -O fsevents | optionalDependencies (--optional) |
| yarn add -D @types/node@22 | A specific major version of the type definitions |
| yarn workspace web add -D vite | Add to one workspace package (Yarn 1 and 2+) |
| yarn remove jest | Remove the package again |
Pitfalls
- Global installs. Yarn 2+ has no
yarn global add; useyarn dlx toolfor one-off commands, or install the tool with npm. Yarn 1 still hasyarn global add. - Workspace root. In a Yarn 1 workspace,
yarn add -D pkgat the root fails unless you confirm with-W(--ignore-workspace-root-check). - Lockfile in CI. After adding a package, commit
yarn.locktoo. CI runsyarn install --immutable(Yarn 2+) or--frozen-lockfile(Yarn 1) and fails when the lockfile is out of date; see package not present in the lockfile. - Wrong Yarn version.
yarn --versionshows which Yarn runs in that folder; projects pin it in thepackageManagerfield ofpackage.json. The Yarn classic vs Berry comparison lists the commands that differ.
How to confirm it worked
cat package.json shows the package under devDependencies, and yarn why package shows that it is installed and which version was resolved. On Yarn 2+, yarn info package prints its resolved version too.
FAQ
What is the difference between yarn add -D and yarn add --dev?
None. -D is the short form of --dev in both Yarn 1 and Yarn 2+. Both write the package to devDependencies in package.json.
Does yarn install skip devDependencies in production?
In Yarn 1, yarn install --production (or NODE_ENV=production) skips them. Yarn 2+ has no --production flag; use yarn workspaces focus --production, which needs the workspace-tools plugin on Yarn 2 and 3 and is built in from Yarn 4.
Why does yarn add say the package is not present in the lockfile?
That error usually comes from a later yarn install --immutable in CI when package.json and yarn.lock disagree. Run yarn install locally, commit yarn.lock, and the check passes.