Your Browser Has a Hard Drive: OPFS and 4 Other Things I Missed

Your Browser Has a Hard Drive (And Four Other Things I Wish I’d Known Sooner)

I’ve been building a bunch of browser-based tools lately. Audio converters, video reducers, watermarkers, document converters. All of them run entirely in your browser, nothing uploaded to a server, and the engine underneath most of them is WebAssembly.

WebAssembly (Wasm for short) is what lets you take a program written in C or Rust, something like ffmpeg, and run it in a browser tab at near-native speed. It’s genuinely amazing. And I leaned on it HARD.

Then I got curious. Was I actually using the right tool, or had I just found one hammer I liked? So I did what I always do when I want a reality check: I fanned the question out to five different AI models and asked them to tear my approach apart.

They agreed on something I did NOT want to hear. 😊

Have you ever gotten really good at one tool and then quietly started using it for everything?

That’s what was happening. Let me show you what I found.

The thing every single model told me first

WebAssembly is not an architecture. It’s one part.

Here’s the analogy that made it click for me. Wasm is a really fast engine. But an engine is not a car. You still need wheels, a fuel tank, and a steering wheel. Bolting a bigger engine onto something that needed better tires doesn’t help.

One of the models put it bluntly: the mistake is moving work into Wasm just because the work involves computing something. That stung a little, because that is EXACTLY the reasoning I’d been using.

So here are the four other pieces, what each one is actually for, and when it beats reaching for Wasm.


1. OPFS: your browser has a hard drive ⚡

This is the one I’m most annoyed I didn’t know about sooner, so it goes first.

OPFS stands for Origin Private File System. Terrible name. What it actually means: your web page gets its own private hard drive inside the browser.

Here’s the analogy. The old way of storing data in a browser (called IndexedDB) is like a filing cabinet with a clerk. You hand the clerk a whole box, they label it and file it away. Want one page out of that box? You ask the clerk, they haul out the ENTIRE box, you dig through it, then hand the whole thing back.

Fine for small boxes. Awful when the box is a 400 MB video.

OPFS hands you the keys to your own storage unit. Walk in, go to shelf 3, grab exactly what you need, put it back, leave. That’s the whole difference: you can read and write specific chunks of a file instead of the whole thing at once.

Why this matters so much for Wasm specifically:

Programs written in C and Rust over the last forty years all assume reading a file is instant. You ask for the bytes, the bytes are there on the very next line. That assumption is baked into SQLite, into ffmpeg, into basically everything.

Browsers don’t work that way. So when you compile that code to Wasm, the tooling has to fake it with a workaround that’s slow and fragile. One of the models called the standard in-memory approach “a toy,” and honestly, that’s the generous read.

OPFS has a mode that gives those programs the instant file access they expect. No faking. That’s why the official browser version of SQLite uses it, and it’s why sites like StackBlitz can run a whole development environment in a tab.

Two things OPFS is NOT ❗

  • It’s not your real filesystem. Nothing written to OPFS shows up in File Explorer. The user can’t see it or open it in another program. It’s invisible scratch space that belongs to the page.
  • It’s not permanent. It lives under a storage quota, and the browser can clear it out if disk space gets tight. Anything the user would be upset to lose needs an export button or a copy on a server.

One catch worth knowing: the fast mode only works in a background thread, never on the main page. That’s deliberate, since a slow disk read on the main thread would freeze the whole UI. Which conveniently forces your heavy work off the main thread, where it belonged anyway. 😃


2. WebGPU: when to hand the work to your graphics card 🚀

Wasm runs on your CPU. Your CPU has maybe 8 or 16 cores. Your graphics card has thousands.

The analogy I like: the CPU is a handful of PhDs. Give them a complicated problem with lots of decisions and they’ll work through it beautifully. The GPU is ten thousand grade schoolers. Give any one of them a hard problem and you get nothing. Give all ten thousand the same simple addition problem at once and they’ll finish before the PhDs have picked up a pencil.

So GPU wins when the work is:

  • The same operation repeated over a LOT of data
  • Heavy on math, light on decision-making
  • Big enough to be worth the setup cost

Image filters, AI model inference, physics, 3D rendering. That’s GPU territory. This is how AI models now run directly in a browser tab with no server involved.

But here’s the trap. Getting data to the graphics card and back costs time. If your job is small, you’ll spend more time shipping the data over than you saved. A tight loop over ten thousand items in Wasm beats a GPU round trip every time.

These two aren’t rivals. The pattern everyone recommended: Wasm is the brain, the GPU is the muscle. Wasm handles the logic, the file format, the undo history. The GPU crunches the pixels. Figma works exactly this way.


3. Plain old JavaScript, running in parallel

This one genuinely surprised me.

I’d assumed Wasm just beats JavaScript, full stop. It’s compiled, it’s low-level, it should win. One model gave me an actual number: well-written JavaScript working on the right kind of data typically lands within 1.5x to 2x of Wasm speed, and sometimes matches it outright.

Then it dropped the example that really got me: Photopea, the free Photoshop clone in your browser, is overwhelmingly hand-tuned JavaScript. So are Excalidraw and tldraw.

And there’s a better point buried in here. Browsers can run several background workers at once. A pool of workers splitting up a job in ordinary JavaScript will beat a single-threaded Wasm module, even though each individual Wasm operation is faster.

Doing four things at once beats doing one thing quickly. That’s not a browser lesson, that’s just a lesson.

There is one real gotcha here. If you want those workers to share memory directly (the fastest way to pass data between them), you have to turn on some strict security headers. Those headers can break third-party embeds and login popups. Every single model flagged this independently, which tells me it bites people constantly.

Worth knowing before you’re debugging why your login stopped working. 😊


4. Just keep it on the server 🤖

This is the unglamorous one, and it’s right more often than any of the above.

If your tool is forms, dashboards, lists, or reports, the server should do the work. You get:

  • One place where the truth lives, so no syncing bugs
  • Google can actually read your pages
  • Analytics that ad blockers can’t hide from you
  • You push a fix and it’s live, no waiting for anyone to reload a cached file
  • It runs fine on a $50 phone

One model estimated developer speed is genuinely 2x to 3x faster for this kind of app. That’s a HUGE amount of time back.

Where it falls apart is anything needing instant feedback. Dragging a slider, drawing, editing audio. A 60 millisecond round trip is invisible when you submit a form and completely unusable when you’re dragging a handle.

The line is simple: can the interaction survive a trip to the server and back? If yes, send it. If no, it has to run locally.


The sneaky good idea nobody else mentioned

One model surfaced something the other four missed, and I think it’s the most interesting thing in the whole pile.

Several server platforms (Cloudflare Workers among them) run WebAssembly too.

Which means the exact same module can run in the browser for an instant preview, AND run on the server for the official version that search engines see. One codebase, two places, no duplicated logic.

I already deploy my tools on Cloudflare. That one’s going on my list. 🚀


The cheat sheet

If you need to…Reach for
Run existing C or Rust code fastWebAssembly
Do the same math over tons of dataWebGPU
Handle big files without eating all the memoryOPFS
Keep the page responsive during heavy workWeb Workers
Build forms, dashboards, or anything SEO matters forKeep it on the server

What I actually took away from this

One of the models said something that stuck with me. The skill isn’t knowing all these technologies. It’s correctly figuring out which 10% of your app is genuinely performance-critical, and only reaching for the heavy tools there.

That’s the same lesson automation keeps teaching me. The win almost never comes from the fanciest possible solution. It comes from correctly identifying the ONE thing that’s actually slow and fixing that.

Don’t get me wrong, I’m not abandoning WebAssembly. For my audio and video tools it’s exactly right. But I was reaching for it out of habit instead of measurement, and OPFS is a real gap I need to go fix.

One more thing worth mentioning about the process itself. Asking five competing AI models the same question and comparing the answers was FAR more useful than asking one. Where they all agreed, I could trust it. Where they disagreed (and they did, sharply, on whether JavaScript can keep up with Wasm) that disagreement told me it’s genuinely situational rather than settled.

That’s a technique I’d recommend for any decision that matters. Don’t ask one AI. Ask several and watch where they split.

How about you? Have you found a tool you’re reaching for out of habit rather than because it’s the right fit? I’d bet you have. I certainly did. ❓


P.S. A quick honesty note. These models quoted specific browser version numbers and support details pretty confidently, and that stuff drifts fast. I’ve deliberately left the version specifics out of this post. If you’re about to build on any of it, go verify current browser support yourself before you commit. Trust, but verify. 😊