Minify CSS/JS — The 5KB That Still Matters on Slow 3G

webdev performance minify css javascript

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

RemovedExample
Whitespace / comments/* todo */, pretty indents
Shortenable CSSmargin: 0 0 0 0margin: 0
Safe JS noiseOptional 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
StepHelps
MinifyFewer raw bytes into compressor
Brotli/gzipWire size
Cache-ControlRepeat visits
HTTP/2 or 3Parallel 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_ENV ships 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.