Staging — blog preview only.
Skip to content

Offline-capable is not sync later if lucky

Scheduled

8 min read By NT²

Many apps call themselves offline-capable when they mean a read-only cache and a queue that hopes the tower returns. A local-first vault puts full CRUD on the device first. Sync is an optional second path.

Offline-capable is not sync later if lucky

Claim: the happy path never asks for a socket

Product copy loves the phrase offline-capable. In practice it often means: the app once downloaded a cache, you can skim stale rows, and writes sit in a queue until connectivity returns—if the queue still works, if the conflict resolver agrees, if the server still recognizes your session.

That is not a happy path. That is a degraded mode with a marketing sticker.

NT² Vault’s claim is sharper:

Create, unlock, read, update, delete, search, attach files, and export a portable backup are complete on the device. No API call is required for daily use. The network is optional—Premium sync and blind relay—not the owner of the vault.

Offline is not a weekend feature. It is the primary architecture. The plane, the embassy basement, the café with captive Wi‑Fi, the hour after a carrier outage: those are normal operating conditions, not edge cases that deserve a spinner and a shrug.

Local-first here is not nostalgia for floppy disks. It is a trust and availability decision: the device that holds the key material is also the device that holds the authoritative structured store. The edge may help replicas converge later. It does not get to decide whether you may add a credential tonight.

Constraint: “sync later” quietly recenters the cloud

The shortcut that kills offline integrity is familiar. Ship a cloud database as source of truth. Add a service worker that caches the last JSON. Label the result offline. When the network fails, writes become “pending,” search becomes incomplete, and unlock starts to smell like a server round-trip.

Three pressures push teams there.

First, product velocity. A single Postgres (or D1-shaped) schema is easy to reason about in a sprint. Client SQLite, OPFS durability, and conflict-aware merge feel expensive until you treat them as the product.

Second, support narratives. Help desks want “check if they are online” and “force a sync.” Those scripts assume the server can see enough to diagnose. A blind edge cannot open items; an honest offline vault cannot be healed by an operator console.

Third, identity collapse. If “log in” means “fetch unlock material and list the vault from the API,” then airplane mode is not merely slow—it is locked out. Collapsing local unlock and cloud authentication into one gesture reintroduces email accounts, password oracles, and a honey pot the architecture was built to refuse.

There is a softer failure mode too: optimistic UI that lies. Showing a green check while the write only exists in an in-memory queue teaches users that the vault “saved.” When the tab dies before flush, or the queue rejects a conflict after reconnect, the happy path was fiction. Offline CRUD must commit locally first—durable on the device—then optionally advertise a replica delta.

The constraint is therefore:

  1. Availability: core vault operations must succeed when the API endpoint is unset or unreachable.
  2. Honesty: sync failures are sync failures, not vault failures.
  3. Identity: unlocking the vault must not depend on authenticating to Workers.

If any of those fail, “offline-capable” is sync-later-if-lucky in a nicer font.

Design: device primary, edge optional

The runtime topology is intentionally boring.

PathWhat runsNeeds network?
Critical pathCreate vault, unlock with master password, item CRUD, local search, attachments, .nt2backup export/importNo
Optional edgeKey DID session, replica batch push/pull, attachment ciphertext sidecars, share/feed relay, billing entitlementsYes — and only when the user opts into Premium sync / relay features

On the device, the vault is a structured local database (WASM SQLite on the Origin Private File System in the browser, or a native file in the desktop shell) plus a separate store for attachment ciphertext. Unlock derives non-extractable keys in memory from the master password and local salt. The list is paged and searched locally. Lock clears keys. None of that waits on Cloudflare.

On the edge, when Premium sync is enabled, the client pushes and pulls opaque replica batches. Workers and object storage see ciphertext frames and account metadata—not item fields. Sync hooks no-op or surface a clear error when offline; they do not block opening a note you already have. Cross-device salt and recovery material travel out-of-band (backup, recovery kit, replica handoff)—not via a “please email me my vault” endpoint.

flowchart LR
  subgraph device [Device — primary]
    UI[Vault UI]
    DB[(Local SQLite + blobs)]
    Key[In-memory CryptoKey]
    UI --> DB
    UI --> Key
  end
  subgraph edge [Edge — optional]
    API[Workers API]
    Hub[Replica hub]
    Store[(Ciphertext store)]
    API --> Hub
    Hub --> Store
  end
  UI -.->|Premium sync when online| API

Two mental models stay separate on purpose. Local unlock answers: may this browser decrypt this vault file? Cloud auth answers: may this Key DID push or pull replica batches for an entitled account? Mixing them is how offline becomes a second-class citizen again. The deeper split is written up in Unlock is local; cloud auth is separate.

Portability without Premium still exists: .nt2backup, offline replica enrollment, and related handoff paths copy encrypted state between devices without asking the edge to become the attic. Sync is convenience and convergence—not the only way a second phone may ever see the vault.

Trade-off: two truths, and a billable sync

Local-first offline happiness has costs we accept in public.

Users learn two layers. Free daily use is the device vault. Cross-device automatic sync is Premium and optional. That is more to explain than “sign in everywhere and we host your life.” It is also the only story consistent with zero-knowledge: if the server never held plaintext, it cannot be the sole recovery desk either.

Conflict and merge live on the client. Blind replica batches converge by design, but the product cannot offer a server-side “show me the conflicting passport title and pick a winner” UI. Operators do not get a vault debugger. Power users who edit the same item on two offline devices will meet merge semantics, not a human support agent reading fields.

First paint still needs a device that has the vault. A brand-new browser profile cannot invent salt and ciphertext from the sky without import, handoff, or a prior sync enrollment. Offline-first is not “zero install ceremony.” It is “after the vault exists on this device, the network is not a dependency.”

Premium is allowed to require the network—for sync. That is not hypocrisy. Charging for blind replica transport is how a low-ARPU product funds edge cost without turning Free into a honey pot of plaintext. The refusal is different: we do not charge for the right to create an item while offline, and we do not degrade Free into read-only theater.

The product story companion to this boundary is Offline by default is not offline-only: local center of gravity, optional blind carrier. This essay is the engineering half—what must be true in the runtime for that story not to be a lie.

What we refuse

Architecture is clearer when the refusals are explicit.

We refuse making the API mandatory for create, unlock, CRUD, search, attachments, or backup. If the happy path needs a socket, the product is cloud-first with a cache.

We refuse unlock-as-login. Master password derivation and local verifier checks stay on the device. Cloud registration and sync sessions use Key DID challenge–response; they do not fetch salt or a decrypt oracle from D1.

We refuse “pending write” as the only durability story. Local commit is authoritative on that device. Sync is best-effort convergence of ciphertext replicas when online and entitled.

We refuse server-side search of secrets and operator “view vault” tools that would make offline integrity irrelevant because the real attic lived in the datacenter anyway.

We refuse calling a read-only cache offline-capable. Skimming last week’s titles while every edit is blocked is not the happy path for a structured vault.

We refuse collapsing Free into a crippled demo that only becomes a vault after billing. Premium buys optional network features. It does not purchase the right to use SQLite on your own disk.

These refusals sit beside the threat and edge essays: residual XSS and device-theft risk stay local and time-bounded (XSS steals sessions elsewhere; here keys are non-extractable); Workers keep a permission list, not a trust speech (What the Workers are allowed to see); replica sync stays blind (Blind replica sync on the edge).

Close: offline as design, not apology

A Progressive Web App can host a serious vault because modern browsers already offer the pieces: private file storage, WASM SQLite, Web Crypto, and a UI that does not need a round-trip to paint a form. The overview of that stack is Why host a heavy server when a PWA can do everything locally?. This post is the availability corollary: once those pieces are primary, airplane mode is not a failure mode.

Offline-capable, done honestly, means the write you made over the Atlantic is already in your database before the seat-back screen finds Wi‑Fi. Sync later—if you want it, if you paid for the blind carrier, if the tower returns—is a second path. Lucky is not part of the contract.

If that ordering matches how you want a private vault to behave—device first, network optional—you can try NT² Vault or read more at nt2.me.

Last updated 2026-11-01

Related stories