Skip to content
BETACurrent release v2025.12Release notesGitHub

The Floppy Rule

If an operating system can fit on a floppy disk, your Hello World application has some explaining to do.

The Floppy Rule: every byte should earn its place. Size isn’t everything, but neither is it nothing.

This is the long version of one of the principles in my software engineering manifesto. It has its own page because other parts of this site, and my projects, keep pointing back at it.

For those of us old enough to remember dial-up internet, floppy disks were once a perfectly ordinary way of distributing software. A little plastic square containing a magnetic disk, with a remarkable capacity of 1,474,560 bytes.

That’s 1.44 MB in the traditional floppy disk sense.

Not gigabytes. Not even tens of megabytes. Just enough space for a few documents, some software, or an impressive collection of questionable MIDI files.

Now here’s something that fascinates me.

You can still fit a working Linux system on one.

In 2025, the FLOPPINUX project demonstrated a working Linux environment using a carefully configured Linux 6.14.11 kernel, BusyBox utilities, and a compressed filesystem, all contained within a single floppy disk image.

It’s not Ubuntu. You’re not going to run Chrome, Docker, and seventeen Electron applications on it. It’s an intentionally stripped-down system with limited functionality.

But it boots. It runs. It’s Linux.

And that makes me look at some modern software and wonder what on earth we’re doing.

It’s a philosophy I’ve developed around building software, particularly small applications, command-line utilities, and standalone binaries.

Start small. Stay small where practical. Make things bigger when there’s a reason.

When I start a project, I want to understand what it actually needs to do, what resources it needs to accomplish that, and whether I’m introducing unnecessary weight along the way.

That might mean questioning whether I need a library to parse three command-line arguments. Whether an entire web framework is justified for a handful of endpoints. Or whether that enormous ORM is really necessary to query two database tables.

Because it’s remarkably easy to start with a simple idea and somehow end up with a 700 MB application.

A package for parsing arguments. Another for displaying colours. One for reading input. An HTTP framework. A dependency injection container. A logging framework with its own dependencies.

Congratulations. We’ve built Hello World.

Don’t you remember dial-up?

The Floppy Rule isn’t a demand that everything must fit within 1.44 MB. It’s a reminder to stop and question what we’re bringing into a project.

This is an important distinction.

I’ve seen developers spend extraordinary amounts of time reducing the size of a binary by a few kilobytes. They introduce complicated build processes, obscure compression tricks, and difficult-to-maintain code to achieve a slightly smaller executable.

That’s not necessarily good engineering either.

A 3 MB application that’s straightforward to build, understand, and maintain might be substantially better than a 1 MB application requiring six hours of compilation and a small ritual sacrifice.

And a 50 MB application that genuinely needs those resources isn’t automatically worse than a 5 MB application.

The objective isn’t to produce the smallest possible software. It’s to avoid unnecessary size and complexity.

A good engineer should be able to explain why something is there.

If adding a dependency increases a binary by 10 MB but saves weeks of development, improves security, and provides genuinely useful functionality, brilliant. That’s a reasonable trade-off.

But if we’re adding 10 MB to avoid writing a straightforward twenty-line function, perhaps we should have another think.

One of the easiest ways to violate the Floppy Rule is through dependencies.

I’m not against them. Libraries, frameworks, and packages are fantastic. They allow us to build on the work of people who’ve already solved difficult problems.

But every dependency comes with a cost.

There’s the obvious cost of size. Then there’s compilation, downloading, maintenance, compatibility, upgrades, licensing, and security.

And dependencies have an irritating habit of bringing their friends.

Perhaps you’ve experienced sitting at your computer on a Thursday evening, watching your CI pipeline download hundreds of packages because you needed a library containing an enum of HTTP status codes.

Or reading about a security vulnerability in a package you’ve never installed, only to discover it’s been quietly sitting six levels deep in your dependency tree for the past eighteen months.

It’s easy to forget that a single dependency can introduce an entire ecosystem of code you neither wrote nor reviewed.

In JavaScript, installing another package is practically muscle memory.

npm install is-even

Lovely. Another dependency.

Before adding one, I try to ask myself whether the standard library already provides what I need, whether the functionality is genuinely complex, and whether the benefit justifies the additional maintenance.

Sometimes the answer is yes.

Sometimes it’s a function that checks whether a number is divisible by two.

The computer has got faster. Have we got lazier?

Section titled “The computer has got faster. Have we got lazier?”

Modern computing is remarkable.

We’ve got multi-core processors, gigabytes of memory, terabytes of storage, and internet connections that would’ve seemed like science fiction when I was growing up.

Yet somehow we’ve managed to create websites that take longer to become usable than pages did over dial-up.

Obviously, modern websites can do considerably more. I’m not comparing a real-time collaborative application to somebody’s GeoCities homepage.

But sometimes we’re downloading several megabytes of JavaScript, fonts, tracking scripts, and framework code just to display some text and a few pictures.

Something has gone a little wrong there.

The same applies to native applications.

We have fast processors and generous amounts of memory, so it’s tempting to stop asking whether we need to allocate another object, load another library, or start another background process.

And yes, that code might run perfectly well on your development machine.

But resources aren’t free simply because they’re plentiful.

Smaller applications can download faster, start sooner, consume less storage, be easier to distribute, and require fewer resources to operate.

That’s especially valuable when you’re building software intended to run on modest hardware, embedded devices, or inexpensive servers.

Let’s imagine an application that runs comfortably on a £10-per-month VPS.

Not terribly expensive.

But after looking at its resource consumption, removing unnecessary allocations, simplifying some queries, and reducing background processing, you discover it’ll run just as comfortably on a £5-per-month VPS.

You’ve saved a fiver.

Not exactly life-changing.

Now imagine you need 100 instances.

That’s £500 per month, or £6,000 per year.

Obviously, real infrastructure costs depend on much more than executable size. CPU, memory, storage, traffic, reliability, and operational requirements all matter.

But the principle remains.

Efficiency has a financial value.

And that’s before considering the electricity, hardware, and resources consumed by operating software at scale.

I’m not advocating spending three weeks shaving nanoseconds off a function that’s called twice a day.

I’m advocating paying attention.

Measure things. Profile them. Understand where the resources are going. Then make sensible improvements.

For me, the rule translates into a handful of practical habits.

Before reaching for a dependency, look at the language’s standard library and the features provided by the operating system.

There’s often considerably more functionality available than people realise.

For a small command-line utility, I love the idea of producing a single executable.

No complicated installation process. No enormous bundled runtime if it can be avoided. No fourteen supporting services.

Just download it, run it, and get on with your day.

That doesn’t mean every application needs to be statically linked or self-contained. Sometimes shared libraries or an existing runtime are the more sensible option.

The important thing is making distribution proportional to the application.

3. Don’t introduce frameworks out of habit

Section titled “3. Don’t introduce frameworks out of habit”

Not every website needs React. Not every API needs an enormous framework. Not every application needs an ORM, Redis, RabbitMQ, and Kubernetes.

I’ve made these mistakes myself, and they’re excellent ways to turn simple projects into complicated ones.

Choose the technology because the application benefits from it, not because it’s familiar, fashionable, or looks impressive on an architectural diagram.

How big is the executable? How many dependencies are included? What’s the startup time? How much memory does it consume?

How much JavaScript does the browser actually download?

You don’t need to obsess over every byte, but you should at least know the answers.

Put the measurements in your build output. Monitor them over time. Make unexpected increases visible.

A sudden 15 MB increase should prompt a question, even if the increase turns out to be perfectly justified.

This might be the most important part.

If an extra dependency improves security, use it. If a larger binary makes development and maintenance considerably easier, that’s worth considering. If a framework genuinely makes the product better, fantastic.

The Floppy Rule is there to encourage thought, not replace it.

I’m not going to spend a week writing my own cryptographic library to save a few megabytes. That would be spectacularly missing the point.

I decided that if I was going to write about this philosophy, I should probably practise what I preach.

So I’ve given this website its own floppy disk budget.

A standard 3.5-inch high-density floppy holds 1,474,560 bytes, and that’s the limit I’ve chosen for the site’s production build.

Not just the HTML on this particular page. The combined output I’m deploying.

The build process measures the output and fails if it exceeds the budget. Here is where it stands, generated by that same build:

Whole build output 1393 KB of 1,440 KB (96.7%)

Every file in the deployed site, 74 files, uncompressed. This is what the budget measures.

This page, as downloaded 29 KB (2.0% of a floppy)

This page's HTML, CSS and JavaScript, gzip-compressed. Search only loads if you use it.

They are different measurements. The build output is everything I deploy, the budget I hold myself to. What a visitor downloads is only the pages they open, and compressed in transit. Showing both keeps me honest.

Could I make the website bigger? Of course.

Would anyone notice if I added another few hundred kilobytes? Perhaps not.

But that’s not really the point.

The constraint encourages me to consider whether I need another font, image, library, or client-side script.

It also encourages me to use the capabilities that browsers already provide. Semantic HTML, CSS, system fonts, and the occasional bit of JavaScript can accomplish an enormous amount.

My project documentation sites have a more generous allowance. They may need search functionality, diagrams, screenshots, and other useful features.

And that’s fine.

The budget should serve the software, not the other way around.

If you’ve read my software engineering manifesto, you’ll know I’m not terribly fond of treating engineering principles as religious commandments.

The Floppy Rule is no exception.

I’m not suggesting everyone should start writing assembly, abandon modern frameworks, or spend their weekends trying to squeeze applications onto obsolete storage media.

Although, admittedly, that does sound like a rather entertaining weekend.

I’m suggesting we should remember that resources have a cost.

Every dependency, allocation, downloaded asset, and background service should have a reason to exist.

Sometimes that reason is performance. Sometimes it’s productivity, security, maintainability, or simply making the software more pleasant to use.

All perfectly valid.

What I don’t particularly like is complexity being introduced without anyone stopping to ask whether it’s necessary.

We’ve become incredibly good at building powerful software.

Perhaps we should occasionally remind ourselves how to build small software too.

The Floppy Rule

Start small. Stay lean. Add what you need. Question what you don’t.

And if your Hello World application is 700 MB, perhaps have a word with yourself.

Support the project: Buy Me a Coffee or GitHub Sponsors.