Zapp Architecture Patterns

The constraints of the Zapp philosophy (no maker-owned servers, no account database, no telemetry) rule out the standard Web 2.0 architectures. The patterns below are the recurring engineering techniques that make Zapps possible anyway.

1. OAuth Device Flow for third-party access

Problem: Some apps need to call third-party services (GitHub, Google Drive, Strava, Spotify) on behalf of the user. The naĂŻve options are both bad:

Better solution: OAuth 2.0 Device Authorisation Grant (RFC 8628), commonly called Device Flow.

Originally designed for TVs and CLI tools that couldn’t run a normal OAuth redirect, Device Flow works perfectly for static client-side apps. The flow:

  1. The Zapp registers as a public OAuth client with the third-party provider (one-time setup; no secret needed for public clients in Device Flow).
  2. When the user clicks “Connect to GitHub” inside the Zapp, the app makes a request to the provider’s device-authorisation endpoint.
  3. The provider returns a user_code and a short verification_uri. The Zapp shows them to the user.
  4. The user opens the URL on any device, signs in, types the code, and approves the scopes they want to grant.
  5. The Zapp polls the token endpoint until the user finishes. It then receives a normal OAuth access token (and usually a refresh token), stored in local storage.

The whole flow runs purely client-side. The maker doesn’t need a backend; the third party handles the auth ceremony. The user enters their actual scoped permission set, not a god-mode PAT they had to figure out how to mint.

Why this beats PAT-pasting

Providers that support Device Flow

For providers that don’t support Device Flow, PKCE-based OAuth (RFC 7636) is the next best option and also works without a backend. PAT-pasting should be a last resort, used only when neither Device Flow nor PKCE is available.

2. The Napkin Pattern (URL state encoding)

Problem: Sharing data between users normally requires a database to hold the shared state.

Solution: Serialise the app’s state to JSON, compress it (LZMA, brotli, or base64), and append it to the URL hash. The receiving client decodes the URL to recreate the exact state locally.

app.com/#state=eJyrVkrLzC1WslJQys9LTU8t...

Caveats to be honest about:

Best used for calculation tools, charts, configurations — payloads under a few kilobytes.

3. The Walkie-Talkie Pattern (P2P networking)

Problem: Real-time collaboration (multiplayer games, shared editing, voice/video) normally requires a centralised signalling server.

Solution: Treat the network like a walkie-talkie, not a cell phone. Use peer-to-peer transports for the data channel, and either local discovery or public infrastructure for signalling:

Privacy caveat the original draft missed: public signalling networks are public. Anyone watching a public DHT or Nostr relay can map which peers are talking to which. If a Zapp uses this pattern for anything privacy-sensitive (private messaging, financial discussions), the metadata is visible to passive observers even though the content isn’t.

For most uses (a local game, a shared classroom session, a casual sketching board) this isn’t a problem. For anything sensitive, P2P over LAN or a self-hosted signalling relay is the right answer.

4. Cloud-storage folder sync (the simplest “sync that just works”)

Problem: Users want their data to follow them across devices without dealing with OAuth or backups.

Solution: Save state files into a folder the user has already configured for cloud sync — iCloud Drive, Google Drive, Dropbox, OneDrive. The Zapp doesn’t manage the sync; the OS does.

Why this is often the best Zapp sync option:

This is the underrated default. Many Zapps that go straight to Git-as-Backend would be better served by writing to a cloud-synced folder.

5. Git as Backend (heavier, more powerful)

Problem: Some users want versioned, structured sync with conflict resolution, and they don’t want to depend on a single cloud-storage provider.

Solution: Use the user’s own GitHub (or GitLab, Codeberg) account as the persistence layer. The Zapp uses OAuth Device Flow to obtain a token, then writes JSON or SQLite state files directly to a private repository via the REST API.

Implications:

Good fit for blogging tools, note-taking, and anything where versioning is genuinely useful. Overkill for a calculator.

6. Naked Data (open file formats only)

Rule: Internal storage may be optimised (IndexedDB, Hive, SQLite WASM). The export must be universal.

Every Zapp should include a one-click export to open, human-readable formats. See Zapp Data Formats for recommended formats per data type.

The Zapp should also actively prompt the user to back up periodically — “It’s been 7 days, download your data” — because relying on volatile browser storage alone is fragile. Modern iOS Safari clears IndexedDB after seven days of no interaction with the site (ITP), so an app the user opens monthly can quietly lose state.

7. Static Hosting Only (with honest limits)

A Zapp web app is a bundle of static files (HTML, CSS, JS, WASM) that any free static host can serve: GitHub Pages, Cloudflare Pages, Netlify free tier. No serverless functions, no databases, no auth providers.

Honest cost limits:

For a popular Zapp, this is enough — most static apps are tiny and cached at edge. For a viral Zapp (millions of users in a week) the host will throttle. The honest answer in that scenario is to fall back to self-hosting on a cheap VPS or to ask users to install the app as a PWA so the static host only serves the initial load.

8. Offline-First as a Strict Requirement

A web Zapp must work offline after first load. Implement a service worker that caches the entire app shell and all required assets. If the user lands on the page once, the app must remain usable forever, even if the user later goes offline or the developer takes the site down.

Things the page-one happy version glossed over:

Where Zapps cannot reach

For a fuller treatment see When Zapps are Wrong. The summary:

Picking a different architecture honestly for these cases is better than faking the philosophy.

See also