.gitignore for Node.js

node_modules/ npm-debug.log* yarn-error.log* coverage/ *.tsbuildinfo .env .env.local .env.*.local

A Node.js .gitignore starts with node_modules/, then the debug logs npm, Yarn and pnpm write, coverage/, TypeScript’s *.tsbuildinfo and your local .env files. Those are the key lines of the tool’s Node.js template; the whole template is 39 lines, and the tool below starts with it.

What the blocks ignore

  • Dependencies: node_modules/, at any depth, so every workspace package’s folder goes too. npm ci rebuilds it from the lockfile.
  • Logs and caches: npm-debug.log*, yarn-error.log*, .eslintcache, .cache/, .parcel-cache/ and *.tsbuildinfo, TypeScript’s incremental build state.
  • Test output: coverage/ and .nyc_output/.
  • Packages: *.tgz, which npm pack writes.
  • Environment files: .env, .env.local and .env.*.local.

The template doesn’t ignore dist/, because Node itself never writes one: add your build folder as a custom line, or pick the Vite or Next.js template as well. Application logs such as logs/app.log need the Logs template.

In a scratch repository with this file, git check-ignore -v -n --no-index names the line that matched each path, or prints :: when none did:

.gitignore:3:node_modules/	packages/web/node_modules/vite/index.js
::	package-lock.json
::	yarn.lock
::	pnpm-lock.yaml
.gitignore:47:.env	.env
.gitignore:49:.env.*.local	.env.production.local
::	.env.production
::	.env.example
::	dist/index.js

Keep the lockfile, and know which .env files are safe

Commit package-lock.json, yarn.lock or pnpm-lock.yaml: npm’s documentation says the lockfile is intended to be committed, and it is what makes npm ci install the same tree everywhere. .env.production and .env.example aren’t ignored either. Vite, for one, loads .env.production in production builds and expects only the .local files to stay out of Git; if yours holds secrets, add .env.* and !.env.example as custom lines.

Yarn’s ! lines depend on .yarn/*

The template ignores .yarn/*, the folder’s contents, then re-includes patches, plugins, releases, sdks and versions. Git never looks inside an excluded directory, so writing .yarn/ instead breaks every one of those lines:

.gitignore:34:.yarn/	.yarn/releases/yarn-4.5.0.cjs

With the template’s .yarn/*, the same path gives ::. These lines follow Yarn’s advice for projects without Zero-Installs; with Zero-Installs, Yarn wants .yarn/cache and .pnp.cjs committed, so drop the .pnp.* line and add !.yarn/cache.

node_modules was committed before the line?

.gitignore only affects untracked files, so a tracked node_modules stays tracked. Untrack it, keeping it on disk, and commit:

git rm -r --cached node_modules
git commit -m "Stop tracking node_modules"

Editor and OS files

.DS_Store, Thumbs.db and editor swap files come from your machine, not from the project. Put them in a global ignore file once, rather than in every repository:

git config --global core.excludesFile ~/.gitignore_global

Without that setting, Git reads ~/.config/git/ignore (or $XDG_CONFIG_HOME/git/ignore).

Try it in the Gitignore Generator

In the file: Node.js

.gitignore

1 template · 39 pattern lines
# Node.js
# Dependencies installed by npm, Yarn, pnpm or Bun
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
.pnpm-debug.log*
lerna-debug.log*
# Diagnostic reports Node writes to the working directory when it crashes
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
*.pid
*.pid.lock
*.seed
lib-cov/
# Coverage reports from c8, nyc or Jest
coverage/
*.lcov
.nyc_output/
.cache/
.parcel-cache/
.grunt/
bower_components/
jspm_packages/
web_modules/
# TypeScript's incremental build cache
*.tsbuildinfo
.eslintcache
.stylelintcache
# Tarballs written by npm pack
*.tgz
.node_repl_history
# Yarn's cache and install state; the five lines below re-include what has to be committed
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
# Yarn's Plug'n'Play files
.pnp.*
.npm/
.lock-waf*
# Native addons built by node-gyp
build/Release/
# Local environment files; commit .env.example instead
.env
.env.local
.env.*.local
  • ✓Not ignored: no line in this file matches "/package-lock.json".

Lines are applied top to bottom, and the last one that matches wins — which is why a line of your own can overrule a template.

Runs in your browser. Nothing you enter is sent anywhere.