Check npm package sizes before you install. Compare alternatives, stay lean. π¦
Installing dependencies without checking their size is like buying a car without checking the gas mileage. pkgsize helps you make informed decisions by showing you exactly how much bloat you're adding to your project.
β
Fast β Uses npm registry API, no installation required
β
Compare β Check multiple packages side-by-side
β
Mobile Impact β See download time on 3G/4G networks
β
Zero dependencies β Uses Node.js built-in fetch
β
Color-coded β Green for small, yellow for medium, red for large
β
JSON output β Easy to integrate with other tools
npm install -g pkgsizeOr use with npx (no installation):
npx pkgsize lodashScenario: You want to check how big lodash is before installing.
$ pkgsize lodash
π Fetching package info...
Package Version Unpacked Tarball Deps
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
lodash 4.17.21 1.4 MB π΄ 547 KB 0
π‘ Large package. Consider alternatives like lodash-es or tree-shakeable imports.Result: 1.4 MB unpacked β pretty heavy for a utility library!
Scenario: You need a date library. moment.js is popular, but is it bloated?
$ pkgsize moment dayjs date-fns
π Fetching package info...
Package Version Unpacked Tarball Deps
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
moment 2.30.1 3.1 MB π΄ 1.0 MB 0
dayjs 1.11.10 178 KB π‘ 72 KB 0
date-fns 3.6.0 2.4 MB π΄ 932 KB 0
π‘ Smallest: dayjs (178 KB unpacked)
Savings vs moment: 94% smaller π
Recommendation: Use dayjs for minimal bundle sizeResult: dayjs is 94% smaller than moment.js β huge win for frontend apps!
Scenario: You need an HTTP client. axios? fetch wrapper? Which is lightest?
$ pkgsize axios got node-fetch ky
π Fetching package info...
Package Version Unpacked Tarball Deps
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
axios 1.6.5 1.2 MB π΄ 447 KB 3
got 14.2.0 1.7 MB π΄ 521 KB 14
node-fetch 3.3.2 124 KB π’ 48 KB 2
ky 1.2.0 87 KB π’ 31 KB 0
π‘ Smallest: ky (87 KB unpacked)
Lightest: ky with 0 dependencies!
Recommendation:
- Modern projects: Use native fetch (built-in, 0 KB!)
- Need polyfill: ky (minimal overhead)
- Feature-rich: axios (but 14x larger than ky)Result: ky is tiny with zero deps, or just use native fetch() for free!
Scenario: Your bundle is too big. Should you replace lodash?
$ pkgsize lodash ramda underscore just-pick
π Fetching package info...
Package Version Unpacked Tarball Deps
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
lodash 4.17.21 1.4 MB π΄ 547 KB 0
ramda 0.30.1 1.1 MB π΄ 438 KB 0
underscore 1.13.6 885 KB π‘ 351 KB 0
just-pick 2.3.0 14 KB π’ 5.2 KB 0
π‘ Smallest: just-pick (14 KB unpacked)
Savings vs lodash: 99% smaller!
Recommendation:
- Need one function: Install specific utility (just-pick, just-map, etc.)
- Need many utilities: Use lodash-es with tree-shaking
- Full lodash: 1.4 MB β only if you REALLY need everythingResult: Micro-libraries like just-* are 99% smaller when you only need one function!
Scenario: You're building a mobile-first app and need to know real-world download times.
$ pkgsize react vue angular --mobile
Package Version Tarball 3G 4G
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
react 19.2.4 55.9 KB 447ms 44ms
vue 3.5.27 796.8 KB 6.4s 622ms
angular 1.8.3 680.3 KB 5.4s 531ms
π‘ Smallest: react (167.6 KB)Result: React loads in under 50ms on 4G, while Vue takes 600ms β matters for first paint!
Note: Times are for tarball download only (not unpacking/parsing). 3G = 1 Mbps, 4G = 10 Mbps.
Scenario: You want to fail CI if dependencies exceed size limits.
$ pkgsize express --json
[
{
"name": "express",
"version": "4.19.2",
"unpackedSize": 220352,
"tarballSize": 91234,
"dependencyCount": 31
}
]CI Script Example:
#!/bin/bash
# Fail if any package > 1 MB
size=$(pkgsize lodash --json | jq '.[0].unpackedSize')
if [ $size -gt 1048576 ]; then
echo "β Package exceeds 1 MB limit: $(($size / 1024)) KB"
exit 1
fi
echo "β
Package size OK: $(($size / 1024)) KB"Result: Automated size checks prevent bloat from sneaking into your project.
Scenario: You need icons. react-icons? heroicons? Which is smallest?
$ pkgsize react-icons heroicons lucide-react
π Fetching package info...
Package Version Unpacked Tarball Deps
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
react-icons 5.3.0 38.7 MB π΄ 5.1 MB 0
heroicons 2.1.5 2.1 MB π΄ 342 KB 0
lucide-react 0.454.0 5.8 MB π΄ 892 KB 0
β οΈ WARNING: react-icons is HUGE (38.7 MB unpacked)
π‘ Alternative approach:
- Use tree-shakeable icon libraries
- Import only icons you need: import { HomeIcon } from 'heroicons/react/24/outline'
- Or use SVG sprite sheets (0 KB runtime!)
Recommendation: heroicons with tree-shaking (imports only used icons)Result: react-icons bundles EVERYTHING. Use selective imports instead!
- π’ Green: < 100 KB (lightweight)
- π‘ Yellow: 100 KB - 1 MB (moderate)
- π΄ Red: > 1 MB (heavy)
| Package | Unpacked Size | Dependencies |
|---|---|---|
| lodash | 1.3 MB | 0 |
| ramda | 1.1 MB | 0 |
| underscore | 885 KB | 0 |
| Package | Unpacked Size | Dependencies |
|---|---|---|
| moment | 2.9 MB | 0 |
| dayjs | 178 KB | 0 |
| date-fns | 2.4 MB | 0 |
| Package | Unpacked Size | Dependencies |
|---|---|---|
| axios | 1.1 MB | 3 |
| node-fetch | 124 KB | 0 |
| got | 1.4 MB | 14 |
You can also use pkgsize programmatically:
import { fetchPackageInfo, formatSize } from 'pkgsize';
const info = await fetchPackageInfo('lodash');
console.log(`${info.name}: ${formatSize(info.unpackedSize)}`);- Queries npm registry API (
https://registry.npmjs.org/{package}) - Fetches metadata for the latest version
- Extracts
unpackedSize,tarballinfo, and dependency count - Displays in a clean, color-coded table
- Shows only the latest version (not all versions)
- Tarball size requires an additional HEAD request (may fail for some packages)
- Dependency tree size is not calculated (only direct dependencies)
Always check package size before adding a dependency:
# Considering adding moment.js?
pkgsize moment dayjs date-fns
# Output shows dayjs is 16x smaller!
# Package Version Unpacked Tarball
# βββββββββββββββββββββββββββββββββββββββββββββ
# moment 2.30.1 2.9 MB 941.2 KB
# dayjs 1.11.13 178.3 KB 74.1 KB
# date-fns 3.6.0 2.4 MB 671.3 KB
# Decision: Use dayjs π
npm install dayjsPrevent bloat with automated checks:
# .github/workflows/size-check.yml
name: Package Size Gate
on: [pull_request]
jobs:
check-new-deps:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}
path: base
- name: Check for new dependencies
run: |
# Get new packages
new_deps=$(diff base/package.json package.json | grep "+" | grep -v "+++" | cut -d'"' -f2)
for pkg in $new_deps; do
echo "Checking $pkg..."
size=$(npx pkgsize "$pkg" --json | jq -r '.[0].unpackedSize')
if [ "$size" -gt 1000000 ]; then
echo "β $pkg is too large: $(echo $size | numfmt --to=iec)B"
echo "Consider alternatives or split the feature."
exit 1
fi
done
echo "β
All new dependencies are reasonably sized"Automate package comparison:
#!/bin/bash
# scripts/compare-alternatives.sh
echo "π Comparing alternatives for: $1"
echo ""
# Read alternatives from arguments
shift
alternatives="$@"
pkgsize $alternatives
echo ""
echo "π‘ Recommendation:"
smallest=$(pkgsize $alternatives --json | jq -s 'min_by(.unpackedSize) | .name' -r)
echo "Use $smallest for minimal bundle impact"Usage:
# Compare HTTP clients
./scripts/compare-alternatives.sh "HTTP client" axios node-fetch got
# Compare state management
./scripts/compare-alternatives.sh "state" redux zustand jotaiGenerate size analysis before optimization:
// scripts/analyze-dependencies.js
const { execSync } = require('child_process');
const { dependencies } = require('../package.json');
console.log('π¦ Dependency Size Analysis\n');
const packages = Object.keys(dependencies);
const results = JSON.parse(
execSync(`npx pkgsize ${packages.join(' ')} --json`).toString()
);
// Sort by size
results.sort((a, b) => b.unpackedSize - a.unpackedSize);
console.log('π΄ Largest Dependencies:');
results.slice(0, 5).forEach((pkg, i) => {
const sizeMB = (pkg.unpackedSize / 1024 / 1024).toFixed(2);
console.log(`${i + 1}. ${pkg.name}: ${sizeMB} MB`);
});
console.log('\nπ‘ Optimization Ideas:');
const large = results.filter(p => p.unpackedSize > 1000000);
if (large.length > 0) {
console.log(`- Consider alternatives for: ${large.map(p => p.name).join(', ')}`);
console.log('- Use code splitting for large libraries');
console.log('- Import only what you need (tree-shaking)');
}{
"scripts": {
"analyze:size": "node scripts/analyze-dependencies.js"
}
}Hook into npm install to warn about large packages:
// scripts/preinstall-check.js
const { execSync } = require('child_process');
const args = process.argv.slice(2);
if (args.length === 0) process.exit(0);
const packages = args.filter(arg => !arg.startsWith('-'));
if (packages.length === 0) process.exit(0);
try {
const results = JSON.parse(
execSync(`npx pkgsize ${packages.join(' ')} --json`).toString()
);
for (const pkg of results) {
const sizeMB = pkg.unpackedSize / 1024 / 1024;
if (sizeMB > 5) {
console.warn(`\nβ οΈ WARNING: ${pkg.name} is very large (${sizeMB.toFixed(2)} MB)`);
console.warn('Consider alternatives or lazy-load this dependency.\n');
} else if (sizeMB > 1) {
console.log(`βΉοΈ ${pkg.name} is ${sizeMB.toFixed(2)} MB`);
}
}
} catch (err) {
// Ignore errors (package might be local or private)
}Add to .npmrc:
preinstall=node scripts/preinstall-check.js
Compare popular alternatives in each category:
# Utils
pkgsize lodash ramda underscore lodash-es
# Date
pkgsize moment dayjs date-fns luxon
# HTTP
pkgsize axios got node-fetch ky
# State management
pkgsize redux zustand jotai recoil
# Form validation
pkgsize yup zod joi ajv
# UUID
pkgsize uuid nanoid short-uuid cuidCreate a cheatsheet:
# Lightweight Alternatives Cheatsheet
| Category | Heavy | Light | Size Reduction |
|----------|-------|-------|----------------|
| Date | moment (2.9MB) | dayjs (178KB) | 94% smaller |
| Utils | lodash (1.3MB) | underscore (885KB) | 32% smaller |
| UUID | uuid (284KB) | nanoid (45KB) | 84% smaller |
| Validation | joi (1.1MB) | zod (548KB) | 50% smaller |Ensure consistency across packages:
# scripts/audit-monorepo-sizes.sh
#!/bin/bash
echo "π¦ Monorepo Dependency Size Audit"
echo "=================================="
echo ""
for pkg in packages/*/package.json; do
dir=$(dirname "$pkg")
name=$(jq -r '.name' "$pkg")
echo "π $name ($dir)"
deps=$(jq -r '.dependencies | keys | .[]' "$pkg" 2>/dev/null)
if [ -n "$deps" ]; then
total=0
while read dep; do
size=$(npx pkgsize "$dep" --json 2>/dev/null | jq '.[0].unpackedSize' 2>/dev/null || echo 0)
total=$((total + size))
done <<< "$deps"
total_mb=$(echo "scale=2; $total / 1024 / 1024" | bc)
echo " Total: ${total_mb}MB"
fi
echo ""
doneBuild an interactive CLI tool:
// scripts/explore-package.js
const readline = require('readline');
const { execSync } = require('child_process');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function ask(question) {
return new Promise(resolve => rl.question(question, resolve));
}
(async () => {
console.log('π Package Size Explorer\n');
while (true) {
const pkg = await ask('Package name (or "quit"): ');
if (pkg.toLowerCase() === 'quit') {
console.log('π Goodbye!');
break;
}
try {
console.log('');
execSync(`npx pkgsize ${pkg}`, { stdio: 'inherit' });
console.log('');
const compare = await ask('Compare with alternatives? (y/n): ');
if (compare.toLowerCase() === 'y') {
const alts = await ask('Alternatives (space-separated): ');
console.log('');
execSync(`npx pkgsize ${pkg} ${alts}`, { stdio: 'inherit' });
console.log('');
}
} catch (err) {
console.error('β Package not found or error occurred\n');
}
}
rl.close();
})();Categorize your dependencies by size:
// scripts/group-by-size.js
const { execSync } = require('child_process');
const { dependencies } = require('../package.json');
const packages = Object.keys(dependencies);
const results = JSON.parse(
execSync(`npx pkgsize ${packages.join(' ')} --json`).toString()
);
const groups = {
tiny: [], // < 100 KB
small: [], // 100 KB - 500 KB
medium: [], // 500 KB - 1 MB
large: [], // 1 MB - 5 MB
huge: [] // > 5 MB
};
for (const pkg of results) {
const sizeKB = pkg.unpackedSize / 1024;
if (sizeKB < 100) groups.tiny.push(pkg);
else if (sizeKB < 500) groups.small.push(pkg);
else if (sizeKB < 1024) groups.medium.push(pkg);
else if (sizeKB < 5120) groups.large.push(pkg);
else groups.huge.push(pkg);
}
console.log('π Dependencies by Size\n');
for (const [group, pkgs] of Object.entries(groups)) {
if (pkgs.length === 0) continue;
console.log(`${group.toUpperCase()} (${pkgs.length})`);
pkgs.forEach(p => {
const size = (p.unpackedSize / 1024).toFixed(1);
console.log(` - ${p.name}: ${size} KB`);
});
console.log('');
}
// Recommendations
if (groups.huge.length > 0) {
console.log('β οΈ Consider lazy-loading or replacing:');
groups.huge.forEach(p => console.log(` - ${p.name}`));
}Track dependency bloat over time:
# .github/workflows/weekly-size-report.yml
name: Weekly Dependency Size Report
on:
schedule:
- cron: '0 9 * * 1' # Every Monday at 9 AM
jobs:
report:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate size report
run: |
echo "# Dependency Size Report - $(date +%Y-%m-%d)" > report.md
echo "" >> report.md
deps=$(jq -r '.dependencies | keys | .[]' package.json)
total=0
for dep in $deps; do
size=$(npx pkgsize "$dep" --json | jq '.[0].unpackedSize')
total=$((total + size))
size_mb=$(echo "scale=2; $size / 1024 / 1024" | bc)
echo "- $dep: ${size_mb}MB" >> report.md
done
total_mb=$(echo "scale=2; $total / 1024 / 1024" | bc)
echo "" >> report.md
echo "**Total: ${total_mb}MB**" >> report.md
- name: Upload report
uses: actions/upload-artifact@v4
with:
name: size-report-$(date +%Y%m%d)
path: report.md
- name: Compare with last week
run: |
# Download last week's report and compare
# Alert if size increased by >10%
echo "π Size trend tracking..."Create a .pkgsizerc or .pkgsizerc.json in your project root:
{
"thresholds": {
"small": 102400,
"medium": 1048576,
"large": 5242880
},
"defaultRegistry": "https://registry.npmjs.org",
"timeout": 5000,
"cache": true,
"cacheDir": ".pkgsize-cache",
"maxConcurrent": 5,
"showDependencies": true,
"showDownloadTime": true,
"network": "4G",
"colorize": true
}Or add to package.json:
{
"name": "my-app",
"pkgsize": {
"thresholds": {
"small": 50000,
"large": 500000
},
"showDownloadTime": true
}
}Config Options:
| Option | Type | Default | Description |
|---|---|---|---|
thresholds.small |
number |
102400 (100KB) |
Max size for green/small |
thresholds.medium |
number |
1048576 (1MB) |
Max size for yellow/medium |
thresholds.large |
number |
5242880 (5MB) |
Max size for red/large |
defaultRegistry |
string |
npm registry | Custom registry URL |
timeout |
number |
5000 |
Request timeout (ms) |
cache |
boolean |
true |
Enable response caching |
cacheDir |
string |
.pkgsize-cache |
Cache directory |
maxConcurrent |
number |
5 |
Max parallel requests |
showDependencies |
boolean |
true |
Show dependency count |
showDownloadTime |
boolean |
false |
Show 3G/4G download estimates |
network |
string |
4G |
Network speed for estimates (3G, 4G, 5G) |
colorize |
boolean |
true |
Use colored output |
Override config with environment variables:
PKGSIZE_REGISTRY=https://registry.npmjs.org pkgsize lodash
PKGSIZE_TIMEOUT=10000 pkgsize react
PKGSIZE_CACHE=false pkgsize vue
PKGSIZE_NETWORK=3G pkgsize --mobile angular# Custom thresholds for this check
pkgsize lodash --threshold-small 50000 --threshold-large 500000
# Disable cache for fresh data
pkgsize react --no-cache
# Show all versions (not just latest)
pkgsize express --all-versions
# Check specific version
pkgsize lodash@4.17.20
# Use custom registry
pkgsize my-pkg --registry https://npm.pkg.github.com
# Output format
pkgsize vue --format json
pkgsize vue --format table
pkgsize vue --format compactpkgsize [packages...] [options]| Flag | Alias | Description |
|---|---|---|
--json |
-j |
Output as JSON |
--mobile |
-m |
Show 3G/4G download times |
--no-cache |
Disable caching | |
--cache-dir <dir> |
Custom cache directory | |
--registry <url> |
-r |
Custom npm registry |
--timeout <ms> |
-t |
Request timeout |
--all-versions |
-a |
Show all versions |
--version <ver> |
-v |
Check specific version |
--threshold-small <bytes> |
Custom small threshold | |
--threshold-large <bytes> |
Custom large threshold | |
--format <type> |
-f |
Output format (table, json, compact) |
--no-color |
Disable colored output | |
--show-deps |
Show dependency tree size | |
--sort-by <field> |
Sort by size, name, deps |
|
--help |
-h |
Show help message |
--version |
Show version number |
# Basic usage
pkgsize lodash
# Compare multiple packages
pkgsize lodash ramda underscore
# Show mobile impact
pkgsize react vue angular --mobile
# JSON output for scripting
pkgsize express --json > express-size.json
# Check specific version
pkgsize lodash@4.17.20
# All versions of a package
pkgsize typescript --all-versions
# Custom registry (private packages)
pkgsize @mycompany/toolkit --registry https://npm.pkg.github.com
# Sort by size
pkgsize react vue angular --sort-by size
# Compact output
pkgsize axios got node-fetch --format compact
# No caching (always fresh)
pkgsize next --no-cache
# Custom thresholds (stricter)
pkgsize lodash --threshold-small 10000 --threshold-large 100000pkgsize caches npm registry responses to speed up repeated queries:
# Default cache location: .pkgsize-cache/
pkgsize lodash # First run: fetches from registry
pkgsize lodash # Second run: instant (from cache)
# Custom cache directory
pkgsize react --cache-dir ~/.cache/pkgsize
# Clear cache
rm -rf .pkgsize-cache
# Disable cache for fresh data
pkgsize vue --no-cacheCache Expiry:
- Default: 24 hours
- Configure in
.pkgsizerc:
{
"cache": true,
"cacheTTL": 86400000
}Check multiple packages efficiently:
# Sequential (slow)
pkgsize react
pkgsize vue
pkgsize angular
# Parallel (fast)
pkgsize react vue angular
# Control concurrency
pkgsize $(cat packages.txt) --max-concurrent 10Check all your dependencies:
# From package.json
jq -r '.dependencies | keys[]' package.json | xargs pkgsize
# Production dependencies only
jq -r '.dependencies | keys[]' package.json | xargs pkgsize --json > deps-size.json
# Dev dependencies
jq -r '.devDependencies | keys[]' package.json | xargs pkgsizeSpeed up CI checks:
# Use cache in CI
- uses: actions/cache@v4
with:
path: .pkgsize-cache
key: pkgsize-${{ hashFiles('package.json') }}
- run: pkgsize $(jq -r '.dependencies | keys | join(" ")' package.json)| Feature | pkgsize | package-size | bundlephobia CLI | cost-of-modules |
|---|---|---|---|---|
| No installation needed | β npx | β | β | β |
| Compare multiple packages | β | β | β | |
| Mobile impact | β 3G/4G times | β | β | β |
| JSON output | β | β | β | β |
| Caching | β | β | β | β |
| Custom registry | β | β | β | β |
| Speed | π’ Fast | π‘ Moderate | π΄ Slow | π‘ Moderate |
| Color-coded | β | β | β | |
| CI-friendly | β | β | β | |
| Dependencies | 0 | 5+ | 10+ | 20+ |
vs. Bundlephobia CLI:
- Faster (no webpack analysis)
- Works offline with cache
- Simpler, focused on package size
vs. package-size:
- Compare multiple packages in one command
- Mobile download time estimates
- Better formatting and colors
vs. cost-of-modules:
- No installation needed (npx)
- Works for packages not in node_modules
- JSON output for automation
Problem: Package doesn't exist or is private.
Solution:
# Check spelling
pkgsize loadsh # β Typo
pkgsize lodash # β
Correct
# Private packages: use custom registry
pkgsize @mycompany/pkg --registry https://npm.pkg.github.com
# Authenticate for private registries
npm login --registry=https://npm.pkg.github.com
pkgsize @mycompany/pkg --registry https://npm.pkg.github.comProblem: Network issues or registry is slow.
Solution:
# Increase timeout
pkgsize lodash --timeout 10000
# Use cache
pkgsize lodash # Uses cache after first fetch
# Check registry status
curl -I https://registry.npmjs.org/lodash
# Use mirror/proxy
pkgsize lodash --registry https://registry.npm.taobao.orgProblem: Different size metrics.
Explanation:
pkgsize shows:
- Unpacked size: Actual disk usage after install
- Tarball size: Download size (compressed)
npm info shows different fields:
dist.unpackedSizeβ matches pkgsize "Unpacked"dist.tarballsize β matches pkgsize "Tarball"
# Verify manually
npm info lodash dist.unpackedSize # Should match pkgsizeProblem: Your project uses an older version.
Solution:
# Check specific version
pkgsize lodash@4.17.20
# Check version from package.json
VERSION=$(jq -r '.dependencies.lodash' package.json)
pkgsize lodash@$VERSION
# Or create a script
# package.json
{
"scripts": {
"check:installed": "node scripts/check-installed-sizes.js"
}
}// scripts/check-installed-sizes.js
const { dependencies } = require('../package.json');
const { execSync } = require('child_process');
const packages = Object.entries(dependencies).map(([name, version]) => {
const cleanVersion = version.replace(/^[\^~]/, '');
return `${name}@${cleanVersion}`;
});
execSync(`npx pkgsize ${packages.join(' ')}`, { stdio: 'inherit' });Problem: Want specific fields only.
Solution:
Use jq to extract data:
# Get just the unpacked size
pkgsize lodash --json | jq '.[0].unpackedSize'
# Get name and size
pkgsize react vue --json | jq -r '.[] | "\(.name): \(.unpackedSize)"'
# Sort by size
pkgsize axios got node-fetch --json | jq 'sort_by(.unpackedSize)'
# Filter packages over 1MB
pkgsize react vue angular --json | jq '.[] | select(.unpackedSize > 1048576)'Problem: ANSI colors cause issues in CI.
Solution:
# Disable colors
pkgsize lodash --no-color
# Or set environment variable
NO_COLOR=1 pkgsize lodash
# Use JSON output
pkgsize lodash --json
# Plain text output
pkgsize lodash --format compact --no-colorProblem: Need to enforce size budgets.
Solution:
#!/bin/bash
# scripts/check-size-budget.sh
MAX_SIZE=1048576 # 1 MB
size=$(npx pkgsize "$1" --json | jq '.[0].unpackedSize')
if [ "$size" -gt "$MAX_SIZE" ]; then
echo "β $1 exceeds size budget: $(($size / 1024)) KB > $(($MAX_SIZE / 1024)) KB"
exit 1
fi
echo "β
$1 is within budget: $(($size / 1024)) KB"Use in CI:
- name: Check package size budget
run: |
./scripts/check-size-budget.sh lodash
./scripts/check-size-budget.sh reactProblem: Package has peer dependencies or optional dependencies.
Explanation:
pkgsize counts dependencies only, not:
peerDependenciesoptionalDependenciesdevDependencies
Workaround:
Check package.json manually:
npm info lodash peerDependencies
npm info lodash optionalDependenciesProblem: Need more detailed analysis.
Solution:
pkgsize shows size only. For detailed analysis, use:
# Install and analyze
npm install lodash
du -sh node_modules/lodash/*
# Or use bundlephobia for bundle analysis
npx bundle-phobia lodash
# Or use package-build-stats
npx package-build-stats lodashpkgsize is optimized for quick comparisons, not deep analysis.
Problem: Package was updated but cache shows old data.
Solution:
# Clear cache
rm -rf .pkgsize-cache
# Or force fresh fetch
pkgsize lodash --no-cache
# Or update cache directory
pkgsize lodash --cache-dir /tmp/pkgsize-cacheAuto-clear cache older than 24h:
# Add to crontab
0 0 * * * find ~/.pkgsize-cache -mtime +1 -deleteAlways verify size impact before adding dependencies:
# Before: npm install lodash
pkgsize lodash # Check size first
# Compare alternatives
pkgsize lodash ramda underscore
# Then install the smallest
npm install underscorePrevent bloat accumulation:
# .github/workflows/size-budget.yml
name: Size Budget
on: [pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check new dependencies
run: |
# Get dependencies from PR
new_deps=$(git diff origin/main package.json | grep '"+' | cut -d'"' -f2)
for dep in $new_deps; do
size=$(npx pkgsize "$dep" --json | jq '.[0].unpackedSize')
if [ "$size" -gt 1048576 ]; then
echo "β $dep is too large ($(($size / 1024))KB)"
exit 1
fi
doneKeep a log of why you chose packages:
# DEPENDENCIES.md
## Why we chose these packages
### dayjs over moment
- Size: 178 KB vs 2.9 MB (94% smaller)
- Checked: 2024-02-10
- Command: `pkgsize moment dayjs`
### ky over axios
- Size: 87 KB vs 1.2 MB (93% smaller)
- Zero dependencies vs 3
- Checked: 2024-02-10Schedule size audits:
# Quarterly audit script
#!/bin/bash
echo "π¦ Dependency Size Audit - $(date +%Y-%m-%d)" > audit.txt
echo "" >> audit.txt
deps=$(jq -r '.dependencies | keys[]' package.json)
pkgsize $deps >> audit.txt
# Flag large packages
echo "" >> audit.txt
echo "β οΈ Large Dependencies (>1MB):" >> audit.txt
pkgsize $deps --json | jq -r '.[] | select(.unpackedSize > 1048576) | "- \(.name): \(.unpackedSize / 1024 / 1024 | round)MB"' >> audit.txtAlways check mobile impact:
# Check with 3G/4G times
pkgsize react react-dom --mobile
# Set strict thresholds for mobile
pkgsize lodash --threshold-large 500000In config:
{
"thresholds": {
"small": 50000,
"medium": 200000,
"large": 500000
},
"showDownloadTime": true,
"network": "3G"
}When possible, choose tree-shakeable packages:
# β Full lodash
npm install lodash
# β
Modular lodash
npm install lodash-es
# β
Individual functions
npm install lodash.debounce lodash.throttle
# Check size difference
pkgsize lodash lodash-es lodash.debounceCreate comparison shortcuts:
{
"scripts": {
"compare:date": "pkgsize moment dayjs date-fns luxon",
"compare:http": "pkgsize axios got node-fetch ky",
"compare:state": "pkgsize redux zustand jotai recoil",
"compare:utils": "pkgsize lodash ramda underscore",
"compare:uuid": "pkgsize uuid nanoid short-uuid cuid"
}
}Run with:
npm run compare:date
npm run compare:httpTrack dependency size over time:
# scripts/track-size.sh
#!/bin/bash
DATE=$(date +%Y-%m-%d)
deps=$(jq -r '.dependencies | keys[]' package.json)
pkgsize $deps --json > "size-reports/$DATE.json"
# Compare with last week
if [ -f "size-reports/$(date -d '7 days ago' +%Y-%m-%d).json" ]; then
echo "π Size changes in last 7 days:"
# ... diff logic
fiRemember: npm package size β bundle size
# npm package size
pkgsize react # 167 KB
# vs. bundled size (minified + gzipped)
# Actual bundle impact might be smaller due to:
# - Tree shaking
# - Minification
# - Gzip compression
# For bundle size, use:
npx bundle-phobia reactUse pkgsize for quick comparisons, Bundlephobia for production bundles.
Define and track budgets:
{
"budgets": {
"totalDependencies": 10485760,
"singlePackage": 1048576,
"criticalPackages": {
"react": 200000,
"react-dom": 500000
}
}
}Enforce with:
# scripts/enforce-budgets.js
const budgets = require('../package.json').budgets;
// ... check logicUse pkgsize as a library:
import { getPackageSize, formatSize } from 'pkgsize';
const info = await getPackageSize('lodash');
console.log(info);
// {
// name: 'lodash',
// version: '4.17.21',
// unpackedSize: 1409704,
// tarballSize: 547480,
// dependencyCount: 0
// }
console.log(formatSize(info.unpackedSize));
// "1.3 MB"import { comparePackages } from 'pkgsize';
const comparison = await comparePackages(['moment', 'dayjs', 'date-fns']);
console.log(comparison.smallest);
// { name: 'dayjs', unpackedSize: 178304 }
console.log(comparison.largest);
// { name: 'moment', unpackedSize: 2909696 }
console.log(comparison.recommendation);
// "Use dayjs (94% smaller than moment)"import { categorizeSize } from 'pkgsize';
const category = categorizeSize(500000, {
small: 100000,
medium: 1000000
});
console.log(category);
// "medium"import { getPackageSize } from 'pkgsize';
const packages = ['react', 'vue', 'angular'];
const results = await Promise.all(
packages.map(pkg => getPackageSize(pkg))
);
const sorted = results.sort((a, b) => a.unpackedSize - b.unpackedSize);
console.log(`Smallest: ${sorted[0].name}`);import { getPackageSize, clearCache } from 'pkgsize';
// First call: fetches from registry
const info1 = await getPackageSize('lodash', { cache: true });
// Second call: instant (from cache)
const info2 = await getPackageSize('lodash', { cache: true });
// Clear cache
await clearCache();- bundlephobia β Bundle size analysis (minified + gzipped)
- package-build-stats β Detailed build statistics
- cost-of-modules β Size of installed modules
- licensecheck β Check dependency licenses
- depcheck β Find unused dependencies
Problem: React app bundle was 2.5 MB (too large for mobile).
Solution:
# Step 1: Identify large dependencies
pkgsize $(jq -r '.dependencies | keys[]' package.json) --json | \
jq 'sort_by(.unpackedSize) | reverse | .[0:10]'
# Found: moment (2.9 MB), lodash (1.3 MB)
# Step 2: Compare alternatives
pkgsize moment dayjs
# dayjs is 94% smaller!
pkgsize lodash lodash-es
# lodash-es is tree-shakeable
# Step 3: Replace
npm uninstall moment lodash
npm install dayjs lodash-es
# Result: Bundle reduced to 1.1 MB (56% smaller)Problem: App took 8+ seconds to load on 3G.
Solution:
# Check mobile impact
pkgsize react-dom axios lodash --mobile
# Found:
# - react-dom: 2.1s on 3G
# - axios: 450ms on 3G
# - lodash: 640ms on 3G
# Replace with lighter alternatives
pkgsize ky underscore --mobile
# - ky: 30ms on 3G (15x faster!)
# - underscore: 350ms on 3G
# Result: Load time reduced to 3.5 secondsPRs welcome! To develop locally:
git clone https://github.com/muin-company/pkgsize.git
cd pkgsize
npm install
npm run build
npm test# Install dependencies
npm install
# Build
npm run build
# Watch mode
npm run dev
# Test
npm test
# Test coverage
npm run test:coverage
# Lint
npm run lint
# Format
npm run format# Unit tests
npm test
# Integration tests
npm run test:integration
# E2E tests
npm run test:e2e
# Watch mode
npm run test:watch- Add tests in
src/__tests__/ - Implement in
src/ - Update README with examples
- Run
npm run build && npm test - Submit PR
MIT Β© muin-company
Error:
β Error: Package "my-package" not found in npm registry
Causes & Solutions:
1. Typo in package name
# Wrong
pkgsize recat
# Correct
pkgsize react2. Scoped package (missing @)
# Wrong
pkgsize muin-company/pkgsize
# Correct
pkgsize @muin-company/pkgsize3. Package is unpublished or private
# Private packages won't work
pkgsize @mycompany/internal-tool
# β 404 Not Found
# Solution: Only works with public npm packages4. Network/registry issues
# Check if npm registry is accessible
curl -I https://registry.npmjs.org/react
# Try with custom registry
NPM_REGISTRY=https://registry.yarnpkg.com pkgsize reactError:
β Error: getaddrinfo ENOTFOUND registry.npmjs.org
Causes:
- No internet connection
- Corporate firewall/proxy
- DNS issues
Solutions:
1. Check internet connection
ping registry.npmjs.org2. Configure proxy
# Set proxy environment variables
export HTTP_PROXY=http://proxy.company.com:8080
export HTTPS_PROXY=http://proxy.company.com:8080
pkgsize react3. Use custom registry
# Use Yarn registry
export NPM_REGISTRY=https://registry.yarnpkg.com
pkgsize react
# Or Taobao mirror (China)
export NPM_REGISTRY=https://registry.npmmirror.com
pkgsize react4. Offline mode (requires cache)
# If you've checked this package before, use cached data
pkgsize react --cacheProblem: pkgsize shows 1 MB, but node_modules shows 5 MB.
Explanation:
pkgsize reports:
- unpackedSize: Package files only (from npm metadata)
- tarballSize: Compressed download size
node_modules includes:
- Transitive dependencies (deps of deps)
- node_modules within node_modules
- OS-specific files
Example:
$ pkgsize express
Package Version Unpacked Tarball Deps
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
express 4.19.2 220 KB 91 KB 31
# But after npm install express:
$ du -sh node_modules/
5.2M node_modules/
# Why? Because express has 31 dependencies!Solution: Check full dependency tree
# See all dependencies
npm ls express
# Calculate total size (MacOS/Linux)
npm install express
du -sh node_modules/Error:
SyntaxError: Unexpected token < in JSON at position 0
Cause: npm registry returned HTML (404 page) instead of JSON.
Solution:
# Verify package exists on npm
npm view <package-name>
# If it exists, registry might be down
# Try again in a few minutes or use mirror
export NPM_REGISTRY=https://registry.yarnpkg.com
pkgsize <package-name>Problem: Some packages take 5-10 seconds to check.
Cause: Large package metadata (many versions/dist-tags).
Example:
# Fast (small metadata)
pkgsize nanoid # ~0.3s
# Slow (huge metadata)
pkgsize typescript # ~5s (100+ versions)Solution:
# Use --no-tarball to skip tarball size fetch (faster)
pkgsize typescript --no-tarball
# Or cache results
pkgsize typescript --cache # Subsequent runs: ~0.1sProblem: Output is monochrome in GitHub Actions/GitLab CI.
Solution:
# Force color output
- run: npx pkgsize react --color
# Or use environment variable
- run: FORCE_COLOR=1 npx pkgsize react
# Or disable colors for cleaner logs
- run: npx pkgsize react --no-colorError:
β Error: Too many packages. Maximum: 20
Solution:
# Split into batches
pkgsize lodash ramda underscore
pkgsize axios got node-fetch
# Or use JSON mode and process separately
pkgsize lodash --json > lodash.json
pkgsize ramda --json > ramda.json
jq -s 'add' lodash.json ramda.jsonProblem: pkgsize checks latest, but you need a specific version.
Current behavior:
pkgsize react # Always checks latest (currently 19.x)Workaround (not yet supported):
# Feature request: Version pinning
# pkgsize react@18.2.0 # Coming soon!
# For now: Check npm manually
npm view react@18.2.0 dist.unpackedSizeUse pkgsize as a Node.js library:
import { fetchPackageInfo, formatSize, comparePackages } from 'pkgsize';
// Check single package
const info = await fetchPackageInfo('lodash');
console.log(`π¦ ${info.name}@${info.version}`);
console.log(`π Size: ${formatSize(info.unpackedSize)}`);
console.log(`π¦ Tarball: ${formatSize(info.tarballSize)}`);
console.log(`π Dependencies: ${info.dependencyCount}`);Output:
π¦ lodash@4.17.21
π Size: 1.4 MB
π¦ Tarball: 547 KB
π Dependencies: 0
import { comparePackages, formatComparison } from 'pkgsize';
const packages = ['moment', 'dayjs', 'date-fns'];
const comparison = await comparePackages(packages);
console.log(formatComparison(comparison));
// Find smallest
const smallest = comparison.reduce((min, pkg) =>
pkg.unpackedSize < min.unpackedSize ? pkg : min
);
console.log(`\nπ‘ Recommended: ${smallest.name}`);
console.log(` Savings: ${((1 - smallest.unpackedSize / comparison[0].unpackedSize) * 100).toFixed(1)}%`);import { fetchPackageInfo } from 'pkgsize';
async function customReport(packageName: string) {
const info = await fetchPackageInfo(packageName);
// Calculate mobile download times
const downloadTime3G = (info.tarballSize / 1024 / 1024 / 1) * 1000; // 1 Mbps
const downloadTime4G = (info.tarballSize / 1024 / 1024 / 10) * 1000; // 10 Mbps
return {
package: info.name,
version: info.version,
unpackedMB: (info.unpackedSize / 1024 / 1024).toFixed(2),
tarballMB: (info.tarballSize / 1024 / 1024).toFixed(2),
download3G: `${downloadTime3G.toFixed(0)}ms`,
download4G: `${downloadTime4G.toFixed(0)}ms`,
dependencies: info.dependencyCount
};
}
// Usage
const report = await customReport('react');
console.table([report]);Output:
βββββββββββ¬ββββββββ¬βββββββββββββ¬ββββββββββββ¬βββββββββββββ¬βββββββββββββ¬βββββββββββββββ
β (index) β package β version β unpackedMB β tarballMB β download3G β download4G β dependencies β
βββββββββββΌββββββββΌβββββββββββββΌββββββββββββΌβββββββββββββΌβββββββββββββΌβββββββββββββββ€
β 0 β 'react' β '19.2.4' β '0.17' β '0.05' β '447ms' β '44ms' β 0 β
βββββββββββ΄ββββββββ΄βββββββββββββ΄ββββββββββββ΄βββββββββββββ΄βββββββββββββ΄βββββββββββββββ
import { fetchPackageInfo } from 'pkgsize';
import * as fs from 'fs';
async function analyzeProject(packageJsonPath: string) {
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
const deps = Object.keys(pkg.dependencies || {});
const results = await Promise.all(
deps.map(async name => {
try {
return await fetchPackageInfo(name);
} catch (err) {
return { name, error: err.message };
}
})
);
// Filter out errors
const valid = results.filter(r => !r.error);
// Calculate totals
const totalSize = valid.reduce((sum, pkg) => sum + pkg.unpackedSize, 0);
const totalDeps = valid.reduce((sum, pkg) => sum + pkg.dependencyCount, 0);
console.log(`π Project Analysis`);
console.log(`βββββββββββββββββββββ`);
console.log(`Total packages: ${valid.length}`);
console.log(`Total unpacked: ${(totalSize / 1024 / 1024).toFixed(2)} MB`);
console.log(`Total dependencies: ${totalDeps}`);
console.log(``);
// Top 5 largest
const sorted = valid.sort((a, b) => b.unpackedSize - a.unpackedSize);
console.log(`π΄ Largest packages:`);
sorted.slice(0, 5).forEach((pkg, i) => {
const sizeMB = (pkg.unpackedSize / 1024 / 1024).toFixed(2);
console.log(`${i + 1}. ${pkg.name}: ${sizeMB} MB`);
});
}
// Usage
analyzeProject('./package.json');import { fetchPackageInfo } from 'pkgsize';
interface SizeLimits {
[key: string]: number; // Max size in bytes
}
async function enforceSize Limits(limits: SizeLimits): Promise<void> {
const failures: string[] = [];
for (const [packageName, maxSize] of Object.entries(limits)) {
const info = await fetchPackageInfo(packageName);
if (info.unpackedSize > maxSize) {
const actual = (info.unpackedSize / 1024).toFixed(1);
const limit = (maxSize / 1024).toFixed(1);
failures.push(
`${packageName}: ${actual} KB (limit: ${limit} KB)`
);
}
}
if (failures.length > 0) {
console.error('β Size limit violations:');
failures.forEach(f => console.error(` - ${f}`));
process.exit(1);
}
console.log('β
All packages within size limits');
}
// Usage
enforceSizeLimits({
'lodash': 1024 * 1024, // 1 MB max
'moment': 2 * 1024 * 1024, // 2 MB max
'react': 500 * 1024 // 500 KB max
});// webpack-pkgsize-plugin.js
const { fetchPackageInfo } = require('pkgsize');
class PkgSizePlugin {
apply(compiler) {
compiler.hooks.beforeCompile.tapAsync('PkgSizePlugin', async (params, callback) => {
console.log('π Checking dependency sizes...\n');
const pkg = require('./package.json');
const deps = Object.keys(pkg.dependencies || {});
const large = [];
for (const dep of deps) {
const info = await fetchPackageInfo(dep);
const sizeMB = info.unpackedSize / 1024 / 1024;
if (sizeMB > 1) {
large.push({ name: dep, size: sizeMB });
}
}
if (large.length > 0) {
console.warn('β οΈ Large dependencies detected:');
large.forEach(({ name, size }) => {
console.warn(` - ${name}: ${size.toFixed(2)} MB`);
});
console.warn(' Consider code splitting or lazy loading.\n');
}
callback();
});
}
}
module.exports = PkgSizePlugin;// webpack.config.js
const PkgSizePlugin = require('./webpack-pkgsize-plugin');
module.exports = {
// ... other config
plugins: [
new PkgSizePlugin()
]
};// vite-plugin-pkgsize.ts
import { Plugin } from 'vite';
import { fetchPackageInfo } from 'pkgsize';
export function pkgsizePlugin(): Plugin {
return {
name: 'vite-plugin-pkgsize',
async buildStart() {
const pkg = require('./package.json');
const deps = Object.keys(pkg.dependencies || {});
const results = await Promise.all(
deps.map(name => fetchPackageInfo(name))
);
const total = results.reduce((sum, r) => sum + r.unpackedSize, 0);
const totalMB = (total / 1024 / 1024).toFixed(2);
console.log(`π¦ Total dependency size: ${totalMB} MB`);
if (total > 10 * 1024 * 1024) {
console.warn('β οΈ Dependencies exceed 10 MB. Consider optimization.');
}
}
};
}// vite.config.ts
import { defineConfig } from 'vite';
import { pkgsizePlugin } from './vite-plugin-pkgsize';
export default defineConfig({
plugins: [pkgsizePlugin()]
});import { fetchPackageInfo } from 'pkgsize';
import * as fs from 'fs';
async function generateMarkdownReport(packages: string[], outputPath: string) {
const results = await Promise.all(
packages.map(name => fetchPackageInfo(name))
);
let markdown = '# Package Size Report\n\n';
markdown += `**Generated:** ${new Date().toISOString()}\n\n`;
markdown += `| Package | Version | Unpacked | Tarball | Dependencies |\n`;
markdown += `|---------|---------|----------|---------|-------------|\n`;
results.forEach(pkg => {
const unpacked = (pkg.unpackedSize / 1024).toFixed(1);
const tarball = (pkg.tarballSize / 1024).toFixed(1);
markdown += `| ${pkg.name} | ${pkg.version} | ${unpacked} KB | ${tarball} KB | ${pkg.dependencyCount} |\n`;
});
markdown += '\n## Summary\n\n';
const total = results.reduce((sum, p) => sum + p.unpackedSize, 0);
markdown += `**Total Size:** ${(total / 1024 / 1024).toFixed(2)} MB\n`;
fs.writeFileSync(outputPath, markdown);
console.log(`β
Report saved to ${outputPath}`);
}
// Usage
const pkg = require('./package.json');
const deps = Object.keys(pkg.dependencies || {});
generateMarkdownReport(deps, 'PACKAGE-SIZES.md');import { fetchPackageInfo } from 'pkgsize';
import * as fs from 'fs';
async function generateHTMLDashboard(packages: string[], outputPath: string) {
const results = await Promise.all(
packages.map(name => fetchPackageInfo(name))
);
const html = `
<!DOCTYPE html>
<html>
<head>
<title>Package Size Dashboard</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background: #4CAF50; color: white; }
.large { background: #ffcccc; }
.medium { background: #ffffcc; }
.small { background: #ccffcc; }
</style>
</head>
<body>
<h1>π¦ Package Size Dashboard</h1>
<p>Generated: ${new Date().toLocaleString()}</p>
<table>
<tr>
<th>Package</th>
<th>Version</th>
<th>Unpacked</th>
<th>Tarball</th>
<th>Dependencies</th>
</tr>
${results.map(pkg => {
const sizeMB = pkg.unpackedSize / 1024 / 1024;
const rowClass = sizeMB > 1 ? 'large' : sizeMB > 0.5 ? 'medium' : 'small';
return `
<tr class="${rowClass}">
<td>${pkg.name}</td>
<td>${pkg.version}</td>
<td>${(pkg.unpackedSize / 1024).toFixed(1)} KB</td>
<td>${(pkg.tarballSize / 1024).toFixed(1)} KB</td>
<td>${pkg.dependencyCount}</td>
</tr>
`;
}).join('')}
</table>
<h2>Summary</h2>
<p><strong>Total Size:</strong> ${(results.reduce((sum, p) => sum + p.unpackedSize, 0) / 1024 / 1024).toFixed(2)} MB</p>
</body>
</html>
`;
fs.writeFileSync(outputPath, html);
console.log(`β
Dashboard saved to ${outputPath}`);
}
// Usage
const pkg = require('./package.json');
const deps = Object.keys(pkg.dependencies || {});
generateHTMLDashboard(deps, 'size-dashboard.html');No. pkgsize shows:
- β Unpacked size - Raw files in node_modules
- β Tarball size - npm download size
Not shown:
- β Bundle size - After webpack/vite/rollup minification
- β Gzipped size - What users actually download
- β Tree-shaken size - After unused code removal
To check bundle size, use:
# Webpack Bundle Analyzer
npm install --save-dev webpack-bundle-analyzer
# Vite
npm run build
# Check dist/ folder size
# Or use bundlephobia.com
open https://bundlephobia.com/package/lodashTarball is compressed (gzip). Example:
Unpacked: 1.4 MB (raw files)
Tarball: 547 KB (compressed for npm download)
When you npm install, npm downloads the tarball, then unpacks it to node_modules.
Not yet. Currently only checks latest version.
Workaround:
# Check specific version manually
npm view react@18.2.0 dist.unpackedSize
npm view react@19.0.0 dist.unpackedSizeComing soon:
# Planned feature
pkgsize react@18.2.0 react@19.0.0No. Only works with public npm registry packages.
Alternative for private packages:
# After installing
npm install @mycompany/private-pkg
# Check size
du -sh node_modules/@mycompany/private-pkgBy design. pkgsize shows direct package size only.
Example:
express (220 KB) + 31 dependencies (~5 MB total)
pkgsize reports 220 KB, not 5 MB.
To see total:
npm install express
du -sh node_modules/Not yet. Requires internet to query npm registry.
Coming soon:
# Cache results for offline use
pkgsize lodash --cacheVery accurate for latest versions. Data comes directly from npm registry metadata.
Note: Sizes may vary slightly after installation due to:
- OS-specific files
- Optional dependencies
- Post-install scripts
Not currently. Uses npm registry only.
Workaround:
# Check yarn registry
curl https://registry.yarnpkg.com/react | jq .dist.unpackedSize
# Check custom registry
curl https://registry.company.com/my-pkg | jq .dist.unpackedSizeDifferent use cases:
| Feature | pkgsize | bundlephobia.com |
|---|---|---|
| CLI tool | β Yes | β No (web only) |
| Bundle size | β No | β Yes |
| Gzip size | β No | β Yes |
| Tree-shaking | β No | β Yes |
| Offline mode | π Coming | β No |
| Compare packages | β Yes | β No |
| CI integration | β Easy |
Use pkgsize for:
- Quick CLI checks
- CI/CD integration
- Comparing alternatives
- Pre-install decisions
Use bundlephobia for:
- Actual bundle impact
- Frontend optimization
- Tree-shaking analysis
pkgsize doesn't resolve peer deps. You need to check manually:
# Check peer dependencies
npm info react peerDependencies
# Then check each one
pkgsize react-dom| Tool | Speed | Accuracy | Features | Dependencies |
|---|---|---|---|---|
| pkgsize | β‘οΈ Fast | β Registry | CLI, JSON, Compare | 0 |
| npm-view | π’ Slow | β Registry | Basic info | npm |
| bundlephobia | π’ Very Slow | β β Build | Bundle size, Gzip | Web |
| package-size | β‘οΈ Fast | CLI | Many | |
| cost-of-modules | π’ Medium | β β Installed | Deep analysis | Many |
Why pkgsize?
- β Zero dependencies - Won't bloat your project
- β Registry-based - No installation required
- β Compare mode - Side-by-side comparison
- β JSON output - Easy CI integration
- β Fast - Direct API calls, no build step
- Version comparison -
pkgsize react@18 react@19 - Offline cache - Save results for offline use
- Dependency tree size - Include transitive deps
- Historic tracking - Size changes over time
- Badge generation - Size badges for README
- GitHub Action - Automated PR size checks
- VS Code extension - Check size on hover
Inspired by:
- bundlephobia - Bundle size analysis
- package-size - CLI size checker
- cost-of-modules - Deep analysis
Made with β€οΈ by muin-company
Because smaller is better.