Minify CSS/JS — The 5KB That Still Matters on Slow 3G
Lighthouse: “Minify CSS.” Eng: “We have HTTP/2 and CDN Brotli.” User on hotel Wi-Fi: spinner. Those statements can all be true. Minify is not obsolete — it is the cheapest win before fancy caching debates.
What minify actually removes
| Removed | Example |
|---|---|
| Whitespace / comments | /* todo */, pretty indents |
| Shortenable CSS | margin: 0 0 0 0 → margin: 0 |
| Safe JS noise | Optional semicolons, local renames in bundlers |
It does not remove unused selectors/modules — that is tree-shaking / PurgeCSS. Compare before/after with a CSS/JS minify tool when a legacy page is still hand-deployed without a bundler.
Stack that still wins
source → minify / bundle → brotli/gzip → cache headers → CDN
| Step | Helps |
|---|---|
| Minify | Fewer raw bytes into compressor |
| Brotli/gzip | Wire size |
| Cache-Control | Repeat visits |
| HTTP/2 or 3 | Parallel transfers |
Skipping minify because “gzip exists” leaves wins on the table. Shape of the savings: an 80KB utility CSS might fall to ~60KB minified and ~8–12KB over Brotli; a 400KB app JS similarly drops hard. Numbers vary; the order does not.
CI gotchas and third parties
- Wrong
NODE_ENVships unminified - CMS templates embed pretty JS
- Chat/analytics snippets arrive fat while your bundle is lean
Checklist: production minify on; source maps uploaded to the error tracker (not public by default); HTML shell audited for third-party tags the same day you enable bundler minify.
Source maps and CSS risks
Upload maps to Sentry/Datadog privately. Public .map next to .js reconstructs sources for anyone.
Aggressive CSS minify can break license comments you meant to keep, ancient hacks, or content: " " tricks. Tailwind/Vite defaults are almost always safe; legacy hand-written CSS deserves a visual regression pass on first enablement.
Minify ≠ hide API keys. Beautifiers exist. Obfuscation is a separate, rarely needed choice for typical SaaS.
Measure, then argue
Record transfer size in Network with cache disabled on a throttled profile before/after. Screenshots of KB saved end the HTTP/2 philosophy debate faster than Slack. HTTP/2 does not create bandwidth — 5KB of comments across 20 files is still 100KB of comments on a contended link.
For apps: fix the bundler. For one-off landings without a build: a careful minify pass is enough. Ship the pipeline in order; argue about micro-frontends after the comments are gone.
HTML and JSON are part of the story too
Teams minify JS/CSS and then ship a 200KB HTML document full of inline state or duplicated JSON-LD. Collapse what you can in the template layer (or stream less). Similarly, pretty-printed config.json on a static host is free size — minify JSON for production artifacts when humans are not meant to read them on the CDN.
The habit is the same: delete characters you do not need, then compress, then cache. Apply it to every text response on the critical path, not only app.js.
License comments
Keep /*! license */ banners when legal requires them — configure terser/cssnano to preserve those patterns. Deleting copyright headers to save 800 bytes is the wrong optimization. Review the minifier config the same day you enable production minify.
Finally: do not minify on Friday by hand as a firefight. If production is unminified, fix the pipeline Monday with a rollback plan — panic paste into a website minifier is how license headers and Angular-style DI strings die.
Bundle analysis
Minify after you remove dead code. Run a bundle analyzer occasionally; minify will not save you from accidentally shipping entire icon sets or locale packs you never use.