Engineering 22 min read

Local-First in 2026: The Seven Ideals, Audited

MMNMNOTE
local-firstbrowser apisopfsfile system accessindexeddbofflineengineering

Reference: Local-First Software: You Own Your Data, in spite of the Cloud — Kleppmann, Wiggins, van Hardenberg & McGranaghan · Onward! 2019 · DOI 10.1145/3359591.3359737

"Local-first" is a marketing word now, and marketing words survive no audit. The term comes from a 2019 paper with seven specific, testable ideals. This is what happens when you score each one against the browser APIs that actually shipped: three pass, three partially pass, and one fails outside Chromium.

The paper is worth reading before the audit, because it did not hedge. Kleppmann, Wiggins, van Hardenberg and McGranaghan published Local-First Software: You Own Your Data, in spite of the Cloud at Onward! 2019, and section 2 introduces them with a sentence that is deliberately a checklist rather than a philosophy: "Here are seven ideals to strive for in local-first software." 1 Then, in section 3.2.1, they made a prediction that has aged into a testable claim: "we speculate that web apps will never be able to provide all the local-first properties we are looking for, due to the fundamental thin-client nature of the platform." 1

Seven years is long enough to check. The interesting result is not that they were right or wrong. It is that they were wrong about the ideals everyone assumed, and right about the one that decides ownership.

What are the seven ideals of local-first software?

The seven ideals are section headings in the paper, and quoting them exactly matters because paraphrases circulate widely. Verbatim: "No Spinners: Your Work at Your Fingertips," "Your Work Is Not Trapped on One Device," "The Network Is Optional," "Seamless Collaboration with Your Colleagues," "The Long Now," "Security and Privacy by Default," and "You Retain Ultimate Ownership and Control." 1

The paper's core move is inverting which copy of your data is authoritative. In a cloud app, the server holds the primary copy and your device holds a cache. Local-first swaps those roles. That inversion is the whole idea, and every ideal is a consequence of it.

The authors also ran this exact audit themselves. Table 1 of the paper scores technologies against the seven ideals with a three-way verdict: meets, partially meets, does not meet. 1 Their conclusion in section 4 was blunt: "As we have shown, none of the existing data layers for application development fully satisfy the local-first ideals." 1 So the audit format below is not an invention. It is the paper's own instrument, pointed at a platform the paper wrote off.

Why did the paper say web apps could never do this?

The 2019 objection was architectural, not a complaint about missing features. The authors acknowledged the offline work already done and still rejected it: "Despite many efforts to make web browsers more offline-friendly (manifests, localStorage, service workers, and Progressive Web Apps, among others), the architecture of web apps remains fundamentally server-centric." 1

Their specific technical complaint is the one worth tracking, because it is the one browsers answered. They observed that in many browsers, clearing cookies also deleted local storage, "while this is not a problem for a cache, it makes the browser's local storage unsuitable for storing data of any long-term importance." 1

That was a fair reading of 2019. It is not a fair reading of 2026, because the platform grew a durability story, a real file system, and a lock manager. Whether that story is good enough is the rest of this post. Kleppmann himself, in the abstract for a 2024 talk, put it mildly: "We have come a long way since my colleagues and I published the local-first essay five years ago." 2

The audit: seven ideals against 2026 browser APIs

Here is the whole audit. Scope matters: this scores a browser app on the open web, with no extension and no native wrapper, as of July 2026. Support data comes from MDN's browser-compat-data, which is vendor-fed and machine-readable, and every version carries its release date. 3

#Ideal (verbatim)Primary APIChromeFirefoxSafariVerdict
1No Spinners: Your Work at Your FingertipsOPFS / IndexedDB86 (2020-10-20)111 (2023-03-14)15.2 (2021-12-13)PASS
2Your Work Is Not Trapped on One DeviceService Worker + a sync relay40 (2015-01-21)44 (2016-01-26)11.1 (2018-04-12)PARTIAL
3The Network Is OptionalService Worker40 (2015-01-21)44 (2016-01-26)11.1 (2018-04-12)PASS
4Seamless Collaboration with Your ColleaguesCRDT library + Web Locks69 (2018-09-04)96 (2022-01-11)15.4 (2022-03-14)PASS (in userland)
5The Long Nownavigator.storage.persist()55 (2016-12-01)57 (2017-11-14)15.2 (2021-12-13)PARTIAL
6Security and Privacy by DefaultWebCrypto37 (2014-08-26)34 (2014-12-01)11 (2017-09-19)PARTIAL
7You Retain Ultimate Ownership and ControlshowSaveFilePicker86 (2020-10-20)not supportednot supportedFAIL

Three pass, three partially pass, one fails. The two hard problems, ideals 6 and 7, are not waiting on an API. They follow from the delivery model, which is exactly what the paper said in different words.

Ideals 1, 3 and 4: the parts that quietly got solved

These three are the paper's strongest 2019 objections, and they are now the platform's clearest wins. Instant local reads and writes, offline operation, and real-time collaboration all work in every current engine, and two of the three have been universally available for years rather than months. This is the half of the prediction that did not survive.

Offline is the least interesting to argue about. Service Worker has been in all three engines since Safari 11.1 shipped on 2018-04-12. 3 Ideal 3 is simply done.

Speed is done differently than people expect. The origin private file system gives a browser app a real file system that, per MDN, "offers in-place write access to its content." 4 But the fast path is narrow: createSyncAccessHandle is, in MDN's words, "only available in Dedicated Web Workers." 5 You get real file performance, in a worker, or you get the slow path.

// worker.js — createSyncAccessHandle is dedicated-worker-only, and OPFS-only.
onmessage = async ({ data }) => {
  const root = await navigator.storage.getDirectory();
  const file = await root.getFileHandle('note.md', { create: true });
  const handle = await file.createSyncAccessHandle();

  const bytes = new TextEncoder().encode(data.text);
  handle.truncate(0);
  handle.write(bytes, { at: 0 });
  handle.flush();   // durable-ish: still inside the browser's storage box
  handle.close();   // always close, or the file stays locked
  postMessage('saved');
};

Collaboration deserves an honest asterisk. It works, but the platform barely helps: conflict-free replicated data types live in userland libraries, and the browser contributes coordination primitives like Web Locks, in all engines since Safari 15.4 on 2022-03-14. 3 Merging two devices' edits is a library problem, and we have taken that apart separately in what happens when two devices edit the same note. Scoring ideal 4 as a platform PASS would be generous; it passes because someone else's code solved it.

Ideal 5, The Long Now: you can request durability, never guarantee it

This is the sharpest gap, and it is the one most "local-first" apps quietly fail. Browser storage is evictable by default. An app can ask for persistence, but it cannot grant itself persistence, and it cannot stop a user or a heuristic from clearing the box.

The WHATWG Storage Standard defines the guarantee precisely: "The user agent cannot clear storage marked as persistent without involvement from the origin or user." 6 That is real protection, and by default you do not have it. A local storage bucket "has a mode, which is 'best-effort' or 'persistent'. It is initially 'best-effort'." 6

Requesting the upgrade is three lines, and the result is not yours to decide.

// You can request durability. You cannot guarantee it.
async function requestDurability() {
  if (!navigator.storage?.persist) return 'unsupported';
  if (await navigator.storage.persisted()) return 'already-persistent';

  // Firefox prompts the user. Chromium and Safari decide silently, from history.
  const granted = await navigator.storage.persist();
  const { usage, quota } = await navigator.storage.estimate();
  return { granted, usage, quota };
}

The grant is a lottery whose rules differ per engine. MDN states it plainly: "In Firefox, when a site chooses to use persistent storage, the user is notified with a UI popup that their permission is requested," while Safari and Chromium-based browsers "automatically approve or deny the request based on the user's history of interaction with the site and do not show any prompts to the user." 7 A new user on a fresh profile has no history, which is exactly when their first notes are most vulnerable.

Under pressure, browsers evict by a "Least Recently Used (LRU) policy," deleting "the data from the least recently used origin." 7 Safari adds a harder rule. WebKit's John Wilander described it in 2020: the browser is "deleting all of a website's script-writable storage after seven days of Safari use without user interaction on the site," which explicitly covers IndexedDB, LocalStorage and Service Worker registrations. 8

Does persistence defeat that seven-day rule? The vendor documentation does not clearly say, and this audit will not pretend otherwise. WebKit's 2023 storage-policy post lists tracking prevention among the eviction triggers and then hedges: "Origin might be excluded from eviction if it has active page at the time of eviction, or its storage is in persistent mode. By default, all origins use a best-effort mode, which means their persistence is not guaranteed and their data can be evicted." 9 "Might" is the operative word, and neither post resolves the interaction. Treat it as unresolved.

Quotas, to be fair to Safari, are generous everywhere. Chromium allows an origin "up to 60% of the total disk size in both persistent and best-effort modes"; Firefox allows the smaller of 10% of disk or a 10 GiB group limit in best-effort mode, rising to 50% of disk for persistent origins; Safari allows roughly 60% of total disk for browser apps. 7 9 Space is not the problem. Permanence is.

Ideal 7: the dilemma that makes "local-first" a marketing word

Ideal 7 fails cross-browser, and it fails in an instructive way. A browser app must choose between two local stores, and in 2026 no cross-browser option gives both speed and user-visible ownership. That trade-off is the entire audit compressed into one decision.

flowchart TD
  A[App writes a note] --> B{Which store?}
  B -->|OPFS or IndexedDB| C[Bytes on disk<br/>not visible to user]
  B -->|File System Access<br/>Chromium only| D[A real file<br/>you can see]
  C --> E{Persistence mode?}
  E -->|best-effort| F[Evictable under<br/>storage pressure]
  E -->|persistent| G[Excluded from<br/>LRU eviction]
  F --> H[Clear site data:<br/>all of it is gone]
  G --> H
  D --> I[Survives the browser]

Figure: the two local stores a browser app can choose. OPFS and IndexedDB put bytes on your disk that the user cannot see, and both modes end at the same place, because clearing site data deletes them regardless of persistence. Only the File System Access path produces a file that outlives the browser, and that path exists only in Chromium.

OPFS is fast and universal, and it is not ownership. MDN is explicit that it is "private to the origin of the page and not visible to the user like the regular file system," that "The OPFS is not intended to be visible to the user," and that "Clearing storage data for the site deletes the OPFS." 4 Bytes on your disk that you cannot see, find, or back up are local. They are not yours in the sense ideal 7 means.

The API that does deliver ideal 7 is Chromium-only. showSaveFilePicker, showOpenFilePicker and showDirectoryPicker are supported in Chrome since version 86 (2020-10-20) and are not supported in Firefox or Safari. 3 So cross-browser code degrades to an export.

async function saveToRealFile(text) {
  if (!('showSaveFilePicker' in window)) {
    // Firefox and Safari: no picker. A download is the honest fallback.
    const blob = new Blob([text], { type: 'text/markdown' });
    const a = Object.assign(document.createElement('a'), {
      href: URL.createObjectURL(blob), download: 'note.md',
    });
    a.click();
    return 'downloaded';
  }
  const handle = await window.showSaveFilePicker({ suggestedName: 'note.md' });
  const writable = await handle.createWritable();
  await writable.write(text);
  await writable.close();
  return 'saved-in-place';
}

This gap is not an oversight, and both engines have said so in public, with reasoning. Mozilla's official standards position on File System Access is negative, and its rationale draws a careful line: "There's a subset of this API we're quite enthusiastic about (in particular providing a read/write API for files and directories as alternative storage endpoint), but it is wrapped together with aspects for which we do not think meaningful end user consent is possible to obtain (in particular cross-site access to the end user's local file system). Overall we consider this harmful therefore, but Mozilla could be supportive of parts, provided this were segmented better." 10

That nuance is routinely lost. The same Mozilla position list is positive on the WHATWG File System specification that defines OPFS, calling it "A storage endpoint with a POSIX-like file system API is a valuable addition to the web platform." 10 Mozilla does not oppose local files. It opposes handing pages the user's disk.

WebKit reached the same place independently. On the standards-positions issue that Apple labeled position: oppose, Anne van Kesteren wrote: "Colleagues and I have discussed this and don't see a way to grant write access to the end user's local file system in a way that safeguards the end user's interests." 11 He added that read access is a different question and "makes sense."

So ideal 7 is blocked by a genuine security disagreement between engine vendors, not by neglect. That is worth sitting with: the ideal that defines ownership is the one the platform's own privacy model resists.

What the audit teaches: the prediction was half right, and the wrong half is famous

The result is an asymmetry. The paper's 2019 prediction fails on the ideals people quote it for and holds on the one that matters most. Speed, offline and collaboration all shipped. Ownership and security by default did not, and no future API will fix them, because the cause is structural.

Ideal 6 is the clearest example. WebCrypto has been in every engine since Safari 11 shipped it unprefixed on 2017-09-19, so the primitives are not missing. 3 The problem is that a web app is re-delivered by its origin on every single visit. Trust in a browser app is therefore continuous rather than one-time: you are not trusting code you installed once and can inspect, you are trusting whatever the origin serves you next time. A native app you already have on disk does not have that property. This is precisely the "fundamentally server-centric" architecture the paper named, and it is why ideal 6 earns a PARTIAL no matter how good the crypto is.

Which turns the audit into a practical rule for anyone building this way. Where the platform passes, use it. Where it fails, do not paper over it with the word "local-first." Say what is true: the bytes are on the device, the browser may evict them, the user cannot see them unless you hand them a file, and the code arrives fresh from a server every time. An honest export path is not a feature; it is the only cross-browser implementation of ideal 7 that exists.

That is also the reason the word deserves the scrutiny. An app can put every byte on your disk, satisfy four ideals cleanly, and still leave you unable to find your own data with a file manager. Both things are true at once, and only an audit separates them. If you want the same question asked of finished products rather than APIs, we scored eight of them on where your notes actually live, and asked which ones keep working when the network fails.

The verdict

A browser app in 2026 can be genuinely local-first on four ideals and honestly partial on two more. It cannot, on today's cross-browser platform, deliver ideal 7 without exporting a file the user can hold. Kleppmann's "never" was too strong, and his reason was right. Build to the audit, disclose the gaps, and the word means something again.

This audit is a reading of vendor documentation and compatibility data, not a certified conformance test. Re-run it before you rely on it; the cells move.

Frequently asked questions

What does local-first actually mean? It means a specific checklist, not a vibe. The 2019 Ink & Switch paper defines seven ideals, from "No Spinners: Your Work at Your Fingertips" to "You Retain Ultimate Ownership and Control." 1 The core idea is inverting authority: your device holds the primary copy of your data, and servers hold secondary copies.

Can I build a local-first app in the browser? Mostly, yes. Against the seven ideals, a 2026 browser app passes on instant local reads and writes, offline operation, and collaboration, and partially passes on multi-device access, durability and security. It fails cross-browser on user-visible ownership, because the file picker exists only in Chromium. 3

Is the File System Access API supported in Firefox and Safari? No. showSaveFilePicker, showOpenFilePicker and showDirectoryPicker ship in Chrome 86 and later and are not supported in either Firefox or Safari. 3 Both engines oppose it deliberately: Mozilla's official position is negative 10 and WebKit labeled its position oppose 11, in both cases over local file system write access.

Can the browser delete my IndexedDB data? Yes. Storage is "best-effort" by default, meaning it can be evicted. 6 Under storage pressure browsers evict by least-recently-used origin. 7 Safari additionally deletes script-writable storage, including IndexedDB, after seven days of browser use without user interaction on the site. 8

What is the difference between OPFS and the File System Access API? OPFS is a fast, private file system that works in every current engine, but it is "not visible to the user like the regular file system," and clearing site data deletes it. 4 The File System Access API writes real files into folders the user picks, which survive the browser entirely, but it is Chromium-only. 3

Does navigator.storage.persist() guarantee my data is never deleted? No. It upgrades storage to persistent mode, which the spec says a user agent "cannot clear without involvement from the origin or user." 6 But you may not get the grant: Firefox prompts the user, while Safari and Chromium decide silently based on your interaction history. 7 Clearing site data still deletes everything.

Does persistent storage stop Safari's seven-day eviction? The documentation does not clearly answer this. WebKit lists tracking prevention as an eviction trigger and says an origin "might be excluded from eviction" if its storage is in persistent mode. 9 The 2020 post announcing the seven-day rule does not mention persistence at all. 8 Treat it as unresolved and test it.

Why do Mozilla and Apple oppose the File System Access API? Both cite user consent and security, not competition. Mozilla considers the specification harmful as bundled because meaningful consent for "cross-site access to the end user's local file system" is not obtainable, while supporting a segmented version. 10 Apple's Anne van Kesteren wrote that colleagues "don't see a way to grant write access to the end user's local file system in a way that safeguards the end user's interests." 11

An ideal you cannot test is a slogan. Seven of them, scored against the APIs that shipped, turn a manifesto back into engineering.


If you want notes that stay plain Markdown on your own device, work offline, and need no account, mnmnote.com opens in a browser tab.

Footnotes

  1. Kleppmann, M., Wiggins, A., van Hardenberg, P., & McGranaghan, M. "Local-First Software: You Own Your Data, in spite of the Cloud." Onward! 2019 (SPLASH '19), ACM, October 23, 2019. DOI 10.1145/3359591.3359737. Paper: https://www.inkandswitch.com/local-first/static/local-first.pdf (§2 seven ideals; §3.2.1 web apps; §4 conclusion). Essay edition: https://www.inkandswitch.com/essay/local-first/. Accessed 2026-07-17. 2 3 4 5 6 7 8

  2. Kleppmann, M. "The past, present, and future of local-first." Talk at Local-First Conference, Berlin, May 30, 2024. https://martin.kleppmann.com/2024/05/30/local-first-conference.html. Accessed 2026-07-17.

  3. MDN browser-compat-data (api/Window.json, api/StorageManager.json, api/FileSystemFileHandle.json, api/LockManager.json, api/ServiceWorker.json, and browsers/*.json for release dates). https://github.com/mdn/browser-compat-data. Accessed 2026-07-17. 2 3 4 5 6 7 8

  4. "Origin private file system." MDN Web Docs. https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system. Accessed 2026-07-17. 2 3

  5. "FileSystemFileHandle: createSyncAccessHandle() method." MDN Web Docs. https://developer.mozilla.org/en-US/docs/Web/API/FileSystemFileHandle/createSyncAccessHandle. Accessed 2026-07-17.

  6. "Storage Standard." WHATWG, §4.5 Storage buckets and §5 Persistence permission. https://storage.spec.whatwg.org/. Accessed 2026-07-17. 2 3 4

  7. "Storage quotas and eviction criteria." MDN Web Docs. https://developer.mozilla.org/en-US/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria. Accessed 2026-07-17. 2 3 4 5

  8. Wilander, J. "Full Third-Party Cookie Blocking and More." WebKit blog, March 24, 2020. https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/. Accessed 2026-07-17. 2 3

  9. Liu, S. "Updates to Storage Policy." WebKit blog, August 10, 2023. https://webkit.org/blog/14403/updates-to-storage-policy/. Accessed 2026-07-17. 2 3

  10. "Mozilla Specification Positions" (activities.yml: id native-file-system, position negative; id fs, position positive). https://mozilla.github.io/standards-positions/. Accessed 2026-07-17. 2 3 4

  11. van Kesteren, A. Comment of February 8, 2023 on "File System Access API (Local Filesystem)," WebKit standards-positions issue #28 (labeled position: oppose). https://github.com/WebKit/standards-positions/issues/28. Accessed 2026-07-17. 2 3