Everything Is Bloated!
We are lucky that our computers have become so powerful. And when I say computers, I mean not just desktops, but also smartphones, tablets, and more. Today, you can buy a 24-core CPU with 128 GB of RAM and multiple terabytes of storage — enough to hold an absurd amount of data. And don’t get me started on GPUs. We’re getting close to photo-realistic video games, and we now run local AI models on consumer hardware.
But we’re also hitting a ceiling.
Moore’s Law — the prediction that the number of transistors on a chip doubles roughly every two years — is clearly slowing down. Companies like Apple are responding creatively by adding dedicated chips for video, AI, and other specialized workloads. More innovations will come, but raw general-purpose gains are no longer guaranteed.
And because of this abundance over the past decade (or more), developers — including myself at times — have grown lazy. We’ve traded light, fast software for quick development cycles. Cross-platform applications built with Electron routinely consume hundreds of megabytes of memory, where we once shipped native applications measured in single-digit megabytes. Execution time has suffered too. Even on powerful machines, everything feels more sluggish — and users are noticing.
I understand why this happened. Building software that runs well across multiple platforms is expensive and time-consuming. But running server software that idles at 1 GB of RAM and burns CPU cycles also has a cost. Every new feature tends to make systems heavier, and that weight compounds over time.
The situation is especially visible on the server side. Kubernetes and Docker ecosystems are powerful, but heavy. It’s not uncommon to see container images weighing several gigabytes. Disk usage explodes quickly — I’ve personally hit storage limits on a 1 TB drive just from container images.
That’s why, over the past few years, I’ve been looking more seriously at technologies like Quarkus and GraalVM — ways to make Java lighter and faster. I’m also exploring JNI to offload particularly memory- or CPU-intensive code to native languages like Zig, shaving off megabytes and cycles where it matters.
I’ve also been diving into Zig more generally. Go is productive and solid, but it isn’t always ideal for performance-critical paths. Even the founder of HashiCorp built his new terminal emulator, Ghostty, in Zig — a notable choice given how much of HashiCorp’s tooling is written in Go.
On the client side, I’m re-evaluating how we build desktop and mobile applications. Kotlin Multiplatform is increasingly compelling. Flutter is another solid option. And if browser-like capabilities are still needed, CEF remains an alternative — it’s the same embedded Chromium framework used by Spotify for their desktop app.
On the container front, avoiding Docker, Inc in favor of Podman or LXC can help. Using Alpine or distroless images, and actively refactoring bloated containers, goes a long way toward reducing footprint.
On the frontend, the same pattern applies. We’ve normalized massive JavaScript frameworks like React and Angular for problems that don’t always require them. For many applications, using lighter approaches such as HTMX combined with Alpine.js can drastically reduce memory usage, page weight, and client-side complexity. Server-driven HTML with small, declarative JavaScript often leads not only to better runtime performance, but also to faster development cycles. Fewer build steps, fewer dependencies, less tooling churn — and code that’s easier to reason about and maintain over time. There is also WebAssembly (Wasm).
In the end, this is just good engineering hygiene. If we neglect performance and resource usage, users suffer — and costs rise. We can do better, and we should.
