Ship the file

The browser is far more powerful than you think.


On the morning I write this, a well-known AI builder shipped a neural text-to-speech engine — the kind of thing that used to demand a GPU server — that runs entirely inside a browser tab. No backend. Just static HTML and JavaScript on a CDN. You clone your own voice by recording into the page, and the whole voice profile — a thousand numbers — rides inside a link you can text to a friend.

His own note on the architecture: "there's no real web server here". I replied that I loved seeing it, because the browser is far more powerful than it seems.

I've been building this way across dozens of apps — most of them a single HTML file you can double-click. He arrived from AI research; I arrived from shipping small tools. Same conclusion, reached independently. When two people come at something from opposite ends and land in the same spot, it's usually a sign it's true. This page is why.

A single-file app is exactly that: one .html file that holds the markup, the styling, and the logic together. Double-click it and it runs. Drag it onto a host and it's live.

No build step. No npm install. No bundler, no backend, no database, no account, nothing phoning home. The file you read is the whole program — and the only runtime it needs is the browser every computer, phone, and tablet already has.

Why it's the right default

Six things you get for free the moment you refuse the server.

  • 1It outlives its tools. Web standards are the most fiercely backwards-compatible platform we've ever built. A single HTML file written today still opens in a decade — no dependency rot, no toolchain that breaks in six months, no framework that gets abandoned out from under you.
  • 2It costs nothing to run, at any scale. Static files sit on a CDN. There's no server to patch, monitor, or pay for. One user or a million cost you the same: roughly nothing.
  • 3Privacy becomes architecture, not a promise. If there's no server, there's nothing to breach and nothing to leak. Your data stays on your device because there's nowhere else for it to go — that's a property of the design, not a line in a policy.
  • 4You actually own it. No subscription can revoke it, no company can sunset it, no login can lock you out. It works offline, on a plane, off a USB stick — and it keeps working long after the company that would have hosted it is gone.
  • 5It's honest. The whole program is right there to read. Anyone can inspect it, fork it, learn from it, and keep it alive. Nothing hides behind a minified bundle or an API you can't see.
  • 6It's the most AI-legible software there is. The whole app fits in front of the model at once — which is exactly what makes it so fast to build and so easy to keep improving. More on that below.

The browser is the runtime

It quietly became a full operating system. Here's what that buys you — and what I've built on each.

Heavy computeWebAssembly

Native C, C++, and Rust libraries compiled to run in the tab at near-native speed. Sheaf edits — and even OCRs — PDFs entirely in the browser with pdf-lib, PDF.js, and Tesseract, no server. The TTS engine above runs its whole model this way.

The GPUWebGL2 & WebGPU

Direct access to the graphics card for real-time image work and neural nets. Muse grades photos through a single WebGL2 shader chain; LocalMind and Crux run language models on WebGPU.

Real AI, on-deviceTransformers.js · WebLLM · ONNX Runtime · wllama

Actual models — chat, transcription, translation, background removal — running locally, weights streamed once from Hugging Face and cached on-device, nothing uploaded. The whole *Local family (ScanLocal, BlurLocal, BabelLocal, VoiceVault), plus LocalMind and kohra.

MediaWebCodecs

Frame-accurate video and audio decode without a media server. Reel plays and steps through video right in the tab — the media bytes never leave your disk.

Real cryptographyWeb Crypto & WASM

Key generation, key exchange, AES-GCM, HMAC — in the browser itself. Mehfil is end-to-end encrypted with Ed25519, X25519, and AES-GCM; cove runs the MLS messaging protocol compiled to WebAssembly; Rotor is a TOTP authenticator whose secrets never leave your device.

Native-like filesFile System Access API & OPFS

Open and save real files on disk, with your permission, like a desktop app. Sheaf saves PDFs in place; Bahi keeps your books in a .khata file on your own disk; Lorewell reads straight from your library folder.

The cloud, on your termsOAuth + BYOK

When you do want a cloud service, you reach it without handing your data to a middleman. Tide (Calendar) and Skim (Gmail) sign you in with Google and then talk to Google directly from the page — a tiny proxy handles only the OAuth handshake and never sees your mail. Or bring your own key: lurutraffic, Muse, and Crux keep your API key locally and call the service themselves.

State without a databaselocalStorage · IndexedDB · the URL · the file itself

Save on the device, or fold the whole state into something portable. colour-mixer encodes an entire mix into a shareable link; Muse writes the edit recipe into the exported photo, so the look travels inside the image; the TTS engine above hides a cloned voice in a URL. A database you never have to run.


Where it bites — and the way around

It isn't magic, and pretending otherwise wastes your time.

And to be clear: I'm not saying servers are going away — I build them all the time. You just may not need one as often as you reach for it.

  • Secrets can't live in the page. Anyone who opens it can read the source, so an API key in the HTML is a key you've published. Fix: BYOK — the user brings their own key, stored locally — or put the key in a tiny proxy the page calls.
  • Some APIs refuse browser calls (CORS). Fix: pick services that allow it, or front the request with a twenty-line proxy on Cloudflare Workers or Val.town. The app stays a single file; the proxy is a separate, boring afterthought.
  • No pop-up dialogs. The browser's built-in alert() and confirm() are ugly and freeze the page. Build your own in-app toast or modal instead — small effort, large difference in how the thing feels.
  • Big models are slow the first time. Cache the weights in IndexedDB or OPFS after the first download and show a real progress bar. You pay the cold start once; every load after is instant.
  • Failures can be silent. A browser app that throws quietly just looks "stuck." Add a global error handler that surfaces the actual message — the highest-leverage ten lines you'll write in any browser app.
  • The real ceiling is shared state. The moment many people must write to one source of truth — a team ledger, accounts across users, live multiplayer — one file on one device isn't enough. That's the honest line where a server earns its place. Even then, keep it thin and blind: an OAuth proxy that only does the handshake, or a relay that forwards ciphertext it can't read. Everything short of that, keep in the file.

Onboarding the AI

The part that feels almost unfair.

Single-file apps are the easiest kind of software for an AI to build and to keep improving — and that isn't a coincidence.

A model works best when the whole problem fits in front of it. A single file is the whole app: no jumping across forty files, no build graph to reason about, no framework conventions to reverse-engineer. It reads the file top to bottom, edits it in place, and hands it back running. The architecture that's kindest to a human reading it is the same one that's kindest to the machine writing it. That's why this posture and the GenAI age fit together so neatly — and why anyone can build now.

Ask for the constraint by name. This is the whole starting prompt:

paste into any chatbot
Build me a single-file HTML app that [does the thing].
One file. No build step, no npm, no backend — just HTML, CSS, and vanilla JavaScript.
Make it work well on my phone too.

Ask for the capability, not a library. Name the platform and the model reaches for the platform instead of reflexively pulling in a framework:

be specific about the power you want
Run the model on-device with WebGPU — nothing should upload.
Save and open files with the File System Access API, like a desktop app.
Keep all state on the device; let me share a view by encoding it into the URL.

Keep the loop tight. When a chat gets confused, start fresh, paste your last working file, and say what to change. Long threads get sticky; the file is your save point.

Grow in layers. Get the smallest version working end to end, then add one capability at a time on top of something that already runs:

the upgrade prompt
Here's my working single-file app: [paste the whole file].
Add [one capability]. Keep it a single file with no build step.
Don't break anything that already works — show me the full updated file.

The rule of thumb: build the simplest thing that's also a real foundation — never a throwaway scaffold you already plan to rip out, and never a speculative abstraction for a problem you don't have yet. Keep it in one file until shared state genuinely forces your hand.


If there's no server, there's nothing to breach. If it's one file, anyone can read it, fork it, and keep it running. If it fits in a tab, an AI can build it with you in an afternoon.

None of that is a limitation you're settling for. It's the point.


Anyone can build.

Ship the file.

naklitechie.com