What is --ignore-scripts?
The --ignore-scripts flag tells npm to skip lifecycle scripts (preinstall, postinstall, prepare) during installation.
1npm ci --ignore-scripts
Why Use It?
Security
Lifecycle scripts can execute arbitrary code on your machine. A compromised package could run malicious scripts during installation. By ignoring scripts, you reduce this attack surface significantly.
Speed
Skipping scripts makes installs faster. No compilation, no downloading binaries, no running setup tasks. This is especially noticeable in CI/CD pipelines where every second counts.
Reproducibility
Script execution can introduce non-determinism. Network requests during postinstall might fail, binary downloads might differ between environments. Skipping scripts makes builds more predictable.
What to Watch Out For
Here's what I learned from implementing --ignore-scripts in a Next.js production project.
Datadog's dd-trace
dd-trace needs its postinstall script. It downloads native binaries required for tracing. If you use --ignore-scripts, you need to install it separately:
1npm ci --ignore-scripts && npm install dd-trace
The second npm install dd-trace runs without --ignore-scripts, allowing its postinstall to execute. This pattern works for any library that requires lifecycle scripts.
Sentry with Next.js (v8+)
Here's something I discovered: @sentry/nextjs v8 and above uses @sentry/bundler-plugin-core for source map uploads. This plugin communicates with Sentry's API directly during the build process.
It doesn't require the @sentry/cli binary.
This means unless you're using Sentry's telemetry features that specifically need the CLI, npm ci --ignore-scripts works fine without any additional installation steps for Sentry.
Before v8, Sentry relied on @sentry/cli which was downloaded during postinstall. That's no longer the case.
husky
husky uses the prepare script to set up Git hooks:
1{2 "scripts": {3 "prepare": "husky install"4 }5}
With --ignore-scripts, this doesn't run. But here's the thing: you don't need husky in production builds. Git hooks are only relevant for local development.
For local development, after cloning the repo, developers need to either:
- Run
npm installwithout--ignore-scriptsonce - Or manually run
npx husky install
In CI/CD for production builds, you can safely use --ignore-scripts and ignore husky entirely.
devDependencies
Don't worry about devDependencies. In production builds, you typically run:
1npm ci --ignore-scripts --omit=dev
Or the container only includes production dependencies. Either way, devDependency scripts won't run in production regardless.
My Workflow
In production CI/CD:
1# Install dependencies without scripts2npm ci --ignore-scripts34# Install specific packages that need postinstall5npm install dd-trace
For local development:
1# Full install with scripts (for husky, etc.)2npm install
Note: npm ci is designed for CI/CD - it deletes node_modules and does a clean install from the lockfile. For local development, npm install is the standard choice.
Which Libraries Need Special Handling?
When evaluating a package, check:
- Does it have a
postinstallscript in package.json? - Does it download native binaries? (like
esbuild,swc,sharp) - Does it compile native code? (packages with
node-gyp)
Common packages that typically need their scripts:
dd-trace- Downloads native tracing binaries (@datadog/native-metrics, @datadog/pprof)playwright- Downloads browser binaries (Chromium, Firefox, WebKit). You can skip this withPLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1and install browsers separately withnpx playwright installsharp- Downloads libvips binariesbcrypt- Compiles native codesqlite3- Compiles native bindingsesbuild- Downloads platform-specific binary. However, if you're using Next.js 12+, you likely don't need it since Next.js uses SWC (not esbuild) as its default compiler. esbuild in your dependencies is probably from other tools like Vite, tsup, or bundlers
Common packages that work fine without scripts:
@sentry/nextjs(v8+) - Uses JS-based bundler pluginhusky- Only needed for local dev- Most pure JavaScript packages
Conclusion
--ignore-scripts is a powerful flag for production builds. It improves security, speeds up installs, and reduces non-determinism.
The key is knowing which packages in your dependency tree actually need their lifecycle scripts. For most pure JavaScript packages, you don't need them. For packages that download or compile native code, install them separately.
Check your package.json, identify the packages that need scripts, and construct your install command accordingly.
