Blog: Keeping @types/* Out of Production — How We Fixed DEP-17
Keeping @types/* Out of Production — How We Fixed DEP-17
Release: v1.0.387
Category: Dependency hygiene / Build quality
What happened
During a routine dependency audit we identified that @types/qrcode was listed under dependencies in package.json rather than devDependencies. While this doesn't cause any visible runtime error, it is a meaningful miscategorisation with real consequences for production builds.
Why it matters
TypeScript @types/* packages are compile-time only
@types/* packages from DefinitelyTyped exist solely to give the TypeScript compiler the type information it needs to check your code at build time. Once your TypeScript source is compiled to JavaScript, those type declarations are no longer referenced — the output JavaScript has no knowledge of them.
Shipping @types/qrcode in production dependencies means:
- Every production
npm installdownloads and installs a package that will never be called at runtime. - Production container images and deployment bundles are larger than they need to be.
- Dependency count thresholds (like our internal DEP-11 check, which flags projects exceeding 30 production deps) are skewed, producing false positives that obscure genuinely necessary production packages.
The numbers
| Before | After | |
|---|---|---|
Production dependencies count | 31 | 30 |
| DEP-11 threshold status | ❌ Over limit (31 > 30) | ✅ Pass (30 = 30) |
@types/qrcode installed in prod | Yes (wasted) | No |
| TypeScript compilation | ✅ Unaffected | ✅ Unaffected |
| Runtime behaviour | ✅ Unaffected | ✅ Unaffected |
The fix
The change is a single move in package.json — from the dependencies block to devDependencies:
// Before (incorrect)
{
"dependencies": {
"@types/qrcode": "^x.x.x"
}
}
// After (correct)
{
"devDependencies": {
"@types/qrcode": "^x.x.x"
}
}
To apply the same fix locally or in any downstream fork, run:
npm remove @types/qrcode
npm install --save-dev @types/qrcode
General rule of thumb
As a project convention, all @types/* packages must live in devDependencies unless there is an exceptional, documented reason otherwise (there essentially never is). Before merging any PR that adds a new type declaration package, verify the target block in package.json:
# Quick check — should return empty for production deps
npm ls --prod | grep '@types/'
If that command returns anything, a @types/* package has been placed in the wrong block.
No action required
This is a build-time housekeeping fix. No API behaviour, no user-facing features, and no runtime logic were changed in this release. Existing deployments do not need to be restarted.