Applications that once fitted comfortably on a phone now consume many times that space, and updates arrive at sizes that would have been unthinkable a decade ago. The growth is structural.

Software is assembled from libraries

Almost nothing is written from scratch. A developer pulls in existing libraries for image handling, networking, analytics, encryption and dozens of other functions.

Each of those libraries brings its own dependencies, and those bring further dependencies, so a modest project can end up carrying a very large tree of code beneath it.

Most of that code is never executed in a typical session, but it ships anyway because determining exactly what can be safely removed is difficult and risky.

Applications carry their own runtimes

Rather than rely on what a device already has, many applications bundle the framework or engine they need so that behaviour is identical everywhere.

That decision removes an entire class of support problems caused by version differences on users' machines, and developers accept the size cost willingly.

It also means several applications on the same device can each carry their own private copy of substantially the same underlying components.

One package serves many devices

Screens vary widely in resolution, so graphical assets are included at several sizes, and any given device uses only the set that matches it.

The same applies to language files, processor architectures and support for older operating system versions that a minority of users still run.

Modern app stores can strip a download to the variant a specific device needs, but only where the developer has structured the package to allow it.

Removing code is riskier than adding it

Deleting an old feature risks breaking something for the users who still depend on it, and the developer often cannot tell how many of those there are.

Adding a new feature carries no such risk, so the incentives push consistently in one direction across many release cycles.

Compatibility code for older systems accumulates in the same way, since the cost of keeping it is diffuse while the cost of dropping it is immediate and specific.

Delivery methods amplify the effect

A differential update sends only the changed portions, which keeps downloads small even when the installed application is large.

Producing those differentials requires the build to be structured so that a small change does not shuffle the entire package, and not every build system achieves that.

Where it does not, a minor fix triggers a full download, which is the most common reason a trivial change arrives as a very large update.