No Servers, No Accounts: What a Fully Client-Side IDE Forces You to Design
NitroIDE has no servers. Not "serverless" — there is no backend at all. No API, no database, no accounts, no containers, no WebSocket tier. The entire IDE — Monaco editor, live preview, console, state watcher, project storage — runs inside your browser tab. Deployment is static files on GitHub Pages behind Cloudflare.
That started as a privacy position: "your code never leaves your machine." But the interesting part isn't the slogan. The interesting part is that the slogan is structural. There's no privacy policy holding the promise together — there's nowhere for your code to go. And that architecture, once you commit to it, forces you to redesign every feature you'd normally take for granted. Here's what it forced on me.
Storage is a local database, and it has real failure modes
There's no user row in Postgres. Projects live in localStorage under a nitro_projects key; preferences, themes, and editor settings sit in their own keys alongside them. That means the browser's storage is the database, with all of a database's responsibilities and none of its tooling:
- Quota is finite. localStorage gives you roughly 5MB per origin, and it's a synchronous API — a big write blocks the main thread. So project saves are small, serialized blobs, and the app has to treat "storage full" as a real error state, not a theoretical one.
- There is no sync. Your projects exist on exactly one device's one browser profile. The honest answer to "sync my projects" is an export: NitroIDE exports the whole session to a ZIP you can take anywhere. Portability through files, not accounts.
- Schema migration is manual. When the project format changes, the code reading it has to handle every old version — there's no migration runner, just versioned parsers in the client.
This deserves its own deep-dive someday (the localStorage patterns are genuinely interesting), but the headline lesson stands: deleting the server doesn't delete the database. It relocates it into the least forgiving database you've ever operated.
Identity without accounts
No server means no login, which means no password resets, no session management, no "forgot your email" flows. Every "who are you" problem has to be solved differently.
API keys for the AI pair programmer live in your localStorage, per provider — they travel straight from your browser to the provider, and no NitroIDE infrastructure ever sees them because none exists. Preferences are local. There is no profile, no avatar, no billing page. The upside is obvious: nothing to breach, nothing to maintain, no GDPR-shaped headaches around user data. The downside is equally real: lose your browser profile and your keys go with it. That's the trade, stated plainly.
Sharing without a backend
If there's no database, where do shared projects live? In the URL. NitroIDE's share links put the code itself into the link — open it and you get a running app instantly, no signup, no fetch, no round trip. The URL is the API.
The constraint this imposes is URL length: you can't share an arbitrarily large project through a link, because browsers and servers cap how long a URL can be. So the share engine compresses aggressively, and the format is designed around that ceiling. It's a fun inversion of normal thinking — usually you design the payload and the transport is someone else's problem. Here the transport is the product, so the payload is designed to fit it.
Trust boundaries all live in the browser
Without a server, there's no trusted middle layer to hide behind. Every trust boundary is drawn in client-side code:
- The live preview runs in an iframe without
allow-same-origin— user code executes on an opaque origin that cannot reach the parent's localStorage, where your projects live. - Everything the iframe tells the parent (console logs, errors, state updates) passes through a strict sanitizer and field validation before it's rendered — the parent never trusts the child, even though both shipped in the same repo.
Normally you'd put some of this logic server-side where the user can't touch it. There is no server-side. So the client code has to be written like it's adversarial — because parts of it literally are.
The honest exceptions: features that "should" need a server
I'll name the places where pure client-side breaks down, because pretending otherwise would be dishonest:
- Contact forms can't send email from a static site. The contact form goes through a tiny Cloudflare Worker that relays to an email API. It's stateless — a mail pipe, not a database; submissions are emailed, never stored. It's the one piece of server-side infrastructure in the whole product, and it's deliberately dumb.
- Security headers can't be set by GitHub Pages. They live at the Cloudflare layer as transform rules — HSTS, nosniff, a permissions policy that disables camera, mic, and geolocation outright.
- Site search, the blog, the RSS feed, the sitemap are all prebuilt static JSON generated by build scripts (search index, blog data from git history) and precached by the service worker. The "backend" is a build step.
- Analytics and donations are third-party embeds: a GA4 tag, a Ko-fi link. No NitroIDE server touches either flow.
Notice the pattern: everything server-shaped is either a stateless relay, a CDN configuration, or a static file. Nothing in the system stores your code.
The tradeoffs, stated plainly
No cross-device sync — that's the big one, and it's a real cost. localStorage quota is a hard ceiling you have to design around. Share links have size limits. Your API keys live in your own browser storage, which raises the stakes on XSS — which is exactly why the sanitizer work matters so much. And some features are simply refused: real-time collaboration needs a server, so there's no fake version of it.
But the wins are structural, not marketing. Hosting costs are effectively zero, which means the product can't die from a billing failure. Latency is zero for everything except the CDN fetch — there's no API round trip to optimize away. And the privacy claim is the strongest kind: not a promise, a property.
What I'd tell anyone building no-server
- Design the local data model first, with versioning from day one. It's your database; treat it like one.
- Export-first thinking. If users can't take their data out as files, you don't have portability — you have a trap.
- The URL is an API. If a feature can live in a link, it should — links are the most portable, most shareable data format ever invented.
- Treat the CDN edge as your only "server." Headers, redirects, caching rules — that's your entire server-side surface. Learn it well.
- Refuse features that need a backend instead of faking them. A missing feature is honest; a fake one is a lie with extra steps.
The absence of infrastructure turned out to be the most opinionated design decision in the whole product. Every feature is a negotiation with what the browser alone can do — and the browser, it turns out, can do almost everything.
Try it
NitroIDE is free, no signup, and your code never leaves your machine: nitroide.com
⭐ If you enjoyed this, star NitroIDE on GitHub: github.com/nitroideofficial/nitroide