If your goal as a modern developer is to ship less JavaScript, it is time to seriously audit your project dependencies. Most of us install a dependency once and never look at it again. It does its job, the tests pass, and we move on. But the web platform keeps moving too, and a surprising number of the libraries sitting in your package.json today are now built directly into the browser.
Just as digital storefronts require fast rendering speeds to maximize sales—much like following high converting ecommerce product page proven steps to reduce friction—web developers must optimize their applications by leveraging native platform updates. In a typical mid-sized application, you can often find between 60KB and 90KB (minified and gzipped) of dependencies that the platform can now handle on its own. Date formatting, HTTP requests, modals, tooltips, and deep cloning were all real gaps a few years ago. Today, they aren’t gaps anymore.
The reason those libraries stick around isn’t laziness. It’s that most teams simply do not know how to ship less JavaScript because they don’t re-audit their dependencies on a Baseline cadence. You check npm audit for security, but “is this library still doing something the browser can’t natively?” is a question that rarely gets asked.
In this article, we will run that audit together to help you ship less JavaScript. Instead of going through dependencies one by one, we will work in clusters, build a small decision framework you can reuse, and stay honest about the cases where the platform still falls short.
What “Baseline” Means When You Want to Ship Less JavaScript
Before we start deleting things to ship less JavaScript, let’s quickly recap what Baseline actually is.
Baseline is an initiative from the WebDX Community Group that tells you how safe a web feature is to use across major browsers (Chrome, Edge, Firefox, and Safari). A feature can be in one of three states:
- Limited availability: The feature hasn’t shipped in all the major engines yet. Not safe to rely on without a fallback.
- Baseline Newly available: The feature has just landed in all major engines. It works for users on up-to-date browsers, but older devices may not have it yet.
- Baseline Widely available: The feature has been in all the major engines for 30 months. At this point, you can reach for it without much thought.
That 30-month gap matters a lot for this audit. A feature that is Widely available is something you can use to replace a third-party library today. You can easily look any feature up on the official MDN Web Docs to check its status.
A Decision Framework Before You Delete Dependencies to Ship Less JavaScript
It is tempting to read “the browser does this now” and start ripping libraries out. Let’s not do that. A swap that looks free on paper can quietly break things for a chunk of your users. Before dropping any library to ship less JavaScript, ask yourself these three critical questions:
- Is the replacement Baseline-safe for my audience? Check your analytics. If a feature is Newly available, it might be fine for a B2B dashboard, but extremely risky for a public-facing site.
- What does the swap actually cost? Dropping a library isn’t always free. If a native feature requires a heavy polyfill, you might actually make your bundle bigger.
- Does the platform feature cover my real use case? Libraries often do more than the platform feature they resemble (e.g.,
axiosdoes more thanfetch).
1. Internationalization: The Easiest Way to Ship Less JavaScript
This is the cluster where you will usually find the most KBs sitting on top of features that are already Widely available. The browser ships a whole family of formatting tools under the Intl namespace. Here are the usual suspects and what replaces them:
timeago.js(1 KB gz) →Intl.RelativeTimeFormatpluralize(2.3 KB gz) →Intl.PluralRulesnumeral(3.9 KB gz) →Intl.NumberFormathumanize-duration(6.6 KB gz) →Intl.DurationFormat- List-joining helpers →
Intl.ListFormat
Native Relative Time
For example, timeago.js exists to turn a timestamp into “3 hours ago”. Intl.RelativeTimeFormat does the exact same thing natively:
JavaScript
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
rtf.format(-1, "day"); // "yesterday"
rtf.format(3, "hour"); // "in 3 hours"
If your app uses the full set of these tools, that is roughly 14 KB gzipped of dependencies you can eliminate to ship less JavaScript today.
2. HTTP Clients: Replacing Axios with Fetch
The browser HTTP libraries people reach for most are axios (17 KB gz) and superagent (19 KB gz). However, for most basic requests, fetch combined with AbortController covers exactly what you need, and both are Widely available.
JavaScript
// axios
const { data } = await axios.get("/api/users");
// fetch
const res = await fetch("/api/users");
const data = await res.json();
If you just do plain GETs and POSTs without needing automatic retries, upload progress bars, or interceptors, dropping axios for a thin fetch wrapper is an incredibly easy way to ship less JavaScript.
3. UI Primitives: Native Modals and Popovers
The libraries here are modal dialogs (a11y-dialog, 1.8 KB gz), tooltip libraries (tippy.js, 14 KB gz), and focus-trap (6.6 KB gz). They get replaced by three powerful platform features: the <dialog> element, the Popover API, and CSS anchor positioning.
A huge amount of modal-related code exists simply to solve accessibility problems. The <dialog> element does all of that for you natively. Calling showModal() traps focus, makes the background inert, allows the Escape key to close the modal, and renders in the Top layer. Between <dialog>, the Popover API, and anchor positioning, this cluster saves you roughly 24 KB gzipped.
4. Lodash Utilities: Grouping and Deep Cloning
Lodash functions show up everywhere, but several common ones now have direct platform equivalents. For example, lodash.clonedeep makes a deep copy of an object. The structuredClone method is the native version, and it’s Widely available:
JavaScript
const original = { user: { name: "Sam", roles: ["admin"] } };
const copy = structuredClone(original);
copy.user.roles.push("editor");
original.user.roles; // ["admin"] (unchanged)
Dropping lodash.clonedeep and lodash.groupby alone saves about 8 KB gzipped, helping you dramatically ship less JavaScript by leaving the full Lodash library behind entirely.
5. Temporal: When Not to Drop a Library Yet
Every cluster so far has ended in “go ahead, drop it.” This one is the exact opposite. Temporal is the long-awaited replacement for JavaScript’s Date object. It reached TC39 Stage 4 recently.
However, Temporal is not Baseline yet. To use it across all browsers today, you absolutely need a polyfill. The official polyfill is about 44 KB gzipped, whereas a lightweight library like dayjs is only about 3 KB gzipped. If you swap dayjs for Temporal plus its polyfill right now, you actually add 41 KB to your bundle. The verdict: keep dayjs for now and revisit Temporal when Safari ships it in a stable release.
How To Run This Audit to Ship Less JavaScript Today
The clusters above are a starting map, but your dependencies are your own. Here is a repeatable process you can run this quarter:
- List Your Production Dependencies: Run
npm ls --omit=dev --depth=0in your terminal. - Measure What Each One Costs: Use a tool like Bundlephobia to see the minified/gzipped size.
- Check The Baseline Status: Verify native replacements on MDN Web Docs.
- Run The Three Questions: Is it safe? What is the cost? Does it cover the exact use case?
None of this is a one-time cleanup. The platform ships new features constantly, and the gap between “you need a library for this” and “the browser does this natively” keeps closing. Build the habit: once a quarter, run the audit, and aggressively ship less JavaScript to give your users a significantly faster, more optimized web experience.


