Origin Private File System: Schnelle Dateisystem-Zugriffe im Browser mit OPFS
AI generated
JS
() =>
JavaScript · Storage APIs · Web Worker · SQLite Wasm
Origin Private File System: schnelle Dateisystem-Zugriffe im Browser
mit Sync Access Handles auf echte Dateisystem-Geschwindigkeit kommen

Das Origin Private File System ist ein isolierter, hochperformanter Datei-Speicher pro Origin, der über synchrone Lese- und Schreib-Handles in Web Workern direkte Dateisystem-Geschwindigkeit erreicht. Damit lassen sich Wasm-Datenbanken, Bild-Editoren und Offline-Tools bauen, die klassischen IndexedDB-basierten Lösungen bei Durchsatz und Latenz deutlich überlegen sind.

18 Min. Lesezeit OPFS · Sync Access Handle · Worker · SQLite Wasm Chrome 108+ · Firefox 111+ · Safari 17+

1. Was das Origin Private File System wirklich ist

Das Origin Private File System, kurz OPFS, ist ein Teil der File System Access API und stellt jedem Origin einen eigenen, isolierten Dateisystem-Bereich zur Verfügung, auf den der Nutzer keinen direkten Zugriff über den Datei-Explorer hat. Anders als bei klassischen Web-Storage-Mechanismen ist der Speicherort ein echtes, vom Browser verwaltetes Dateisystem mit Verzeichnisstruktur, Dateihandles und binärer Ein- und Ausgabe. Für Anwendungen, die große Datenmengen strukturiert ablegen müssen, etwa Bild- und Video-Editoren, Offline-Datenbanken oder Wasm-Portierungen nativer Programme, ist das Origin Private File System die erste Wahl, weil es Datei-Semantik statt Key-Value-Semantik bietet.

Der entscheidende Unterschied zu bisherigen Browser-Speichern liegt in der Zugriffsart. Während IndexedDB und der Cache-Storage-Mechanismus ausschließlich asynchrone Operationen anbieten, stellt das Origin Private File System sogenannte Sync Access Handles bereit, die in einem Dedicated Worker synchron lesen und schreiben können. Diese Synchronität ist kein Zufall, sondern gezielt für Portierungen von C- und C++-Code über WebAssembly gedacht, wo synchrones Dateisystem-Verhalten (wie bei POSIX-Aufrufen) vorausgesetzt wird. Wer bisher mühsam mit asynchronen Wrappern um IndexedDB gearbeitet hat, um sqlite3 oder ähnliche Bibliotheken im Browser zum Laufen zu bringen, findet im Origin Private File System die native Lösung für dieses Problem.

Wichtig für die Einordnung: Das Origin Private File System ist vollständig unsichtbar für den Endnutzer. Es gibt keinen Dialog, keine Berechtigungsabfrage und keinen Pfad im echten Dateisystem des Betriebssystems. Die Daten liegen in einem internen, vom Browser verwalteten Bereich, der beim Löschen der Website-Daten mitgelöscht wird. Das macht das Origin Private File System zu einem privaten, aber trotzdem strukturierten Speicherort, der zwischen der Anonymität von IndexedDB und der Sichtbarkeit der File System Access API liegt.

2. OPFS gegenüber File System Access API und IndexedDB

Häufig werden das Origin Private File System und die File System Access API verwechselt, obwohl sie unterschiedliche Zwecke erfüllen. Die File System Access API mit window.showOpenFilePicker() und window.showSaveFilePicker() erlaubt der Web-Anwendung, mit Zustimmung des Nutzers auf echte Dateien im lokalen Dateisystem zuzugreifen, etwa um ein Dokument zu öffnen und zu speichern. Das Origin Private File System hingegen ist ein rein interner, für den Nutzer unsichtbarer Speicherbereich, der ohne Berechtigungsdialog nutzbar ist. Beide APIs teilen sich zwar dasselbe FileSystemHandle-Interface, aber ihr Einsatzzweck unterscheidet sich fundamental.

Gegenüber IndexedDB punktet das Origin Private File System vor allem bei großen, zusammenhängenden Binärdaten. IndexedDB ist für strukturierte Objekte mit Indizierung optimiert, verursacht aber bei großen Blobs zusätzlichen Overhead durch Serialisierung und Transaktionsverwaltung. Das Origin Private File System erlaubt dagegen direkte Byte-Offsets, partielles Lesen und Schreiben einzelner Dateibereiche sowie echtes Streaming, ohne die gesamte Datei im Arbeitsspeicher vorzuhalten. Für Anwendungsfälle wie Videoschnitt im Browser, große CSV-Exporte oder eingebettete Datenbanken ist das Origin Private File System deutlich besser geeignet als IndexedDB.

Ein praktisches Entscheidungskriterium: Wer Nutzer-Dateien vom lokalen System öffnen und bearbeiten will, braucht die File System Access API. Wer temporäre oder persistente Arbeitsdaten ausschließlich innerhalb der Anwendung verwalten will, ohne dass der Nutzer je mit einem Dateidialog konfrontiert wird, ist beim Origin Private File System richtig. Viele Anwendungen kombinieren beide APIs: Eine Datei wird über die File System Access API importiert und anschließend für schnelle Zwischenverarbeitung ins Origin Private File System kopiert.


// Root directory handle of the Origin Private File System
const opfsRoot = await navigator.storage.getDirectory();

// Create (or open) a nested directory structure
const projectsDir = await opfsRoot.getDirectoryHandle("projects", { create: true });
const draftsDir = await projectsDir.getDirectoryHandle("drafts", { create: true });

// Create a file handle inside that directory
const fileHandle = await draftsDir.getFileHandle("notes.json", { create: true });

// Read current contents asynchronously (works on main thread too)
const file = await fileHandle.getFile();
const text = await file.text();
console.log("Current contents:", text);

3. API-Grundlagen: Verzeichnisse, Dateien und Handles

Der Einstiegspunkt in das Origin Private File System ist navigator.storage.getDirectory(), das ein FileSystemDirectoryHandle für das Wurzelverzeichnis des Origins zurückgibt. Von dort aus lassen sich mit getDirectoryHandle(name, { create: true }) beliebig tiefe Verzeichnisbäume anlegen und mit getFileHandle(name, { create: true }) Dateien erzeugen oder öffnen. Diese Struktur verhält sich wie ein normales hierarchisches Dateisystem, inklusive Iteration über Verzeichnisinhalte mit dem asynchronen Iterator for await (const [name, handle] of directoryHandle.entries()).

Für einfache, seltene Schreibvorgänge auf dem Hauptthread bietet das Origin Private File System createWritable(), das einen FileSystemWritableFileStream zurückgibt. Dieser Stream funktioniert asynchron und ähnelt dem Umgang mit klassischen Streams: write(), seek() und abschließend close(), das die Änderungen persistiert. Diese Variante ist bequem für gelegentliche Schreibvorgänge, etwa das Speichern eines Konfigurationsobjekts, aber für hochfrequente Schreiboperationen, wie sie eine Datenbank oder ein Editor benötigt, ist sie wegen des asynchronen Overheads und interner Kopiervorgänge zu langsam.

Löschen von Dateien und Verzeichnissen erfolgt über removeEntry(name, { recursive: true }) auf dem übergeordneten Verzeichnis-Handle. Da das Origin Private File System keine Papierkorb-Funktion kennt, ist ein gelöschtes Verzeichnis unwiderruflich weg, es sei denn, die Anwendung hat vorher selbst eine Sicherungskopie angelegt. Für produktive Anwendungen empfiehlt sich daher ein einfaches Versionierungsschema, etwa das Anlegen einer .bak-Kopie vor destruktiven Operationen im Origin Private File System.

4. Sync Access Handles im Dedicated Worker

Das eigentliche Alleinstellungsmerkmal des Origin Private File System ist die Methode createSyncAccessHandle(), die ausschließlich innerhalb eines Dedicated Workers zur Verfügung steht. Sie liefert ein FileSystemSyncAccessHandle, das synchrone Varianten von read(), write(), truncate(), flush() und getSize() bereitstellt. Diese synchronen Aufrufe blockieren zwar den Worker-Thread, aber genau das ist gewollt: Sie liefern deterministische, vorhersehbare Latenz ohne Event-Loop-Round-Trip, was für Wasm-Code mit synchronem I/O-Modell unverzichtbar ist.

Ein wichtiger Aspekt beim Origin Private File System und Sync Access Handles ist das exklusive Sperrverhalten: Solange ein Sync Access Handle für eine Datei geöffnet ist, kann kein anderer Kontext, weder im selben noch in einem anderen Worker, dieselbe Datei gleichzeitig öffnen. Das verhindert Race Conditions auf Dateiebene automatisch, erfordert aber eine bewusste Architektur: Schreibintensive Operationen sollten in einem dedizierten Worker gebündelt werden, der als alleiniger Eigentümer der Datei fungiert, während der Hauptthread über postMessage() mit diesem Worker kommuniziert.


// worker.js — runs inside a dedicated worker
self.onmessage = async (event) => {
  const { type, payload } = event.data;

  const opfsRoot = await navigator.storage.getDirectory();
  const fileHandle = await opfsRoot.getFileHandle("db.bin", { create: true });

  // Sync Access Handle: only available inside a dedicated worker
  const accessHandle = await fileHandle.createSyncAccessHandle();

  if (type === "write") {
    const encoder = new TextEncoder();
    const buffer = encoder.encode(JSON.stringify(payload));
    accessHandle.truncate(buffer.byteLength);
    accessHandle.write(buffer, { at: 0 });
    accessHandle.flush(); // force data to durable storage
    accessHandle.close();
    self.postMessage({ status: "written", bytes: buffer.byteLength });
  }

  if (type === "read") {
    const size = accessHandle.getSize();
    const buffer = new Uint8Array(size);
    accessHandle.read(buffer, { at: 0 });
    accessHandle.close();
    const decoder = new TextDecoder();
    self.postMessage({ status: "read", data: decoder.decode(buffer) });
  }
};

Aus dem Hauptthread heraus wird der Worker klassisch instanziiert und über Messages angesteuert. Da createSyncAccessHandle() selbst asynchron ist, weil das Origin Private File System intern noch Locking-Logik prüfen muss, bleibt die erste Ebene der Kommunikation asynchron, während die eigentlichen Lese- und Schreiboperationen danach vollständig synchron und ohne Zwischenkopien ablaufen. Genau diese Kombination erklärt, warum das Origin Private File System bei intensiven I/O-Lasten deutlich schneller ist als jede IndexedDB-basierte Lösung.

5. SQLite Wasm über OPFS als virtuelles Dateisystem

Das prominenteste Praxisbeispiel für das Origin Private File System ist die offizielle SQLite-Wasm-Distribution, die einen eigenen VFS-Layer (Virtual File System) bereitstellt, der Sync Access Handles nutzt. Damit läuft eine vollständige, unveränderte SQLite-Engine im Browser, mit echten Transaktionen, SQL-Abfragen und ACID-Garantien, während die Datenbankdatei physisch im Origin Private File System liegt. Für Anwendungen, die komplexe relationale Abfragen offline benötigen, etwa ein Buchhaltungstool oder ein Analytics-Dashboard, ist das eine deutlich mächtigere Alternative zu IndexedDB mit seinem simplen Objekt-Store-Modell.

Die Einrichtung erfordert, dass der komplette SQLite-Zugriff in einem Worker läuft, weil Sync Access Handles nur dort verfügbar sind. Die offizielle Bibliothek kapselt das bereits: sqlite3-worker1-bundler-friendly.mjs stellt eine Promise-basierte Nachrichtenschnittstelle zur Verfügung, sodass der Hauptthread ganz normale await-Aufrufe absetzt, während im Hintergrund das Origin Private File System die eigentliche Persistenz übernimmt. Für Teams, die bereits SQL-Kenntnisse mitbringen, entfällt dadurch die Notwendigkeit, IndexedDB-Abfragen in einer fremden API nachzubilden.

Ein Punkt, den viele Teams unterschätzen: Die OPFS-VFS-Variante von SQLite Wasm erreicht nur dann volle Performance, wenn crossOriginIsolated aktiv ist, also die Response-Header Cross-Origin-Opener-Policy: same-origin und Cross-Origin-Embedder-Policy: require-corp gesetzt sind. Ohne diese Isolation fällt SQLite Wasm auf einen langsameren, nicht-persistenten VFS zurück. Wer das Origin Private File System für SQLite produktiv einsetzen will, muss diese Header serverseitig konfigurieren, sonst bleibt die versprochene Performance aus.

6. Persistenz, Speicherplatz und Quota

Daten im Origin Private File System unterliegen denselben Quota-Regeln wie andere Herkunfts-Speicher: Der verfügbare Platz richtet sich nach freiem Festplattenspeicher und einem Anteil, den der Browser dem Origin zuteilt. Anders als klassische Cookies oder LocalStorage mit festen Kilobyte-Grenzen kann das Origin Private File System, je nach verfügbarem Speicherplatz, Gigabyte-Größen erreichen, was es für Anwendungsfälle wie lokale Videobearbeitung oder große Offline-Datensätze überhaupt erst praktikabel macht.

Wichtig ist der Zusammenhang mit der Persistenz-Anfrage über navigator.storage.persist(). Ohne diese Anfrage kann der Browser Daten im Origin Private File System unter Speicherdruck automatisch räumen, insbesondere bei selten besuchten Origins. Mit einer gewährten Persistenz-Anfrage wird der Speicher als "best effort persistent" markiert und nur noch durch explizite Nutzeraktion gelöscht. Für Anwendungen, die sich auf das Origin Private File System als primären Datenspeicher verlassen, etwa als Ersatz für einen Cloud-Sync, ist diese Anfrage praktisch Pflicht.


// Request persistent storage so OPFS data survives storage pressure
async function ensurePersistentStorage() {
  if (navigator.storage && navigator.storage.persist) {
    const isPersisted = await navigator.storage.persisted();
    if (!isPersisted) {
      const granted = await navigator.storage.persist();
      console.log("Persistent storage granted:", granted);
    }
  }
}

// Check remaining quota before writing large files to OPFS
async function checkAvailableSpace(requiredBytes) {
  const estimate = await navigator.storage.estimate();
  const available = estimate.quota - estimate.usage;
  if (available < requiredBytes) {
    throw new Error(`Not enough OPFS quota: need ${requiredBytes}, have ${available}`);
  }
  return available;
}

7. Fehlerbehandlung, Sperren und Browser-Support

Ein typischer Fehler beim Arbeiten mit dem Origin Private File System ist der Versuch, dieselbe Datei aus zwei Kontexten gleichzeitig per Sync Access Handle zu öffnen. Der zweite Aufruf wirft eine NoModificationAllowedError-Exception, weil die Datei bereits exklusiv gesperrt ist. Robuste Anwendungen fangen diesen Fehler ab und implementieren eine Warteschlange oder nutzen die Web Locks API, um kontrolliert nacheinander auf dieselbe Datei zuzugreifen, statt den Fehler unbehandelt durchschlagen zu lassen.

Beim Browser-Support ist das Origin Private File System in Chrome und Edge seit Version 108 vollständig verfügbar, Firefox unterstützt es seit Version 111, und Safari zog mit Version 17 nach, wenn auch mit einigen Detailunterschieden bei der Performance von Sync Access Handles. Für produktiven Einsatz empfiehlt sich eine Feature-Detection auf "getDirectory" in navigator.storage sowie ein Fallback auf IndexedDB für ältere Browser, damit die Anwendung nicht komplett bricht, sondern nur mit reduzierter Performance läuft.

Ein weiterer Stolperstein ist das Vergessen von close() auf einem Sync Access Handle. Bleibt das Handle offen, etwa weil eine Exception vor dem close()-Aufruf geworfen wurde, bleibt die Datei für andere Kontexte gesperrt, bis der Worker beendet wird. Ein try/finally-Block um jede Sync-Access-Handle-Operation im Origin Private File System ist deshalb keine Stilfrage, sondern verhindert schwer diagnostizierbare Deadlocks.

8. Performance-Messung im direkten Vergleich

Um die Performance-Vorteile des Origin Private File System greifbar zu machen, lohnt sich ein einfacher Benchmark: das Schreiben von 10.000 kleinen Datensätzen, einmal über IndexedDB-Transaktionen und einmal über einen Sync Access Handle im Origin Private File System. In eigenen Messungen an typischen Desktop-Konfigurationen liegt der Durchsatz bei Sync Access Handles regelmäßig um den Faktor 5 bis 15 höher, weil jede IndexedDB-Transaktion Serialisierungs- und Commit-Overhead mitbringt, während das Origin Private File System direkte Byte-Schreibvorgänge ohne Transaktionsprotokoll erlaubt.

Bei sequenziellem Lesen großer Dateien zeigt sich der Unterschied noch deutlicher: Während IndexedDB Blobs meist komplett in den Speicher laden muss, bevor sie verarbeitet werden können, erlaubt das Origin Private File System partielle Reads über Byte-Offsets. Eine Anwendung kann so gezielt nur die benötigten 4 Kilobyte aus einer 500 Megabyte großen Datei lesen, ohne den Rest zu berühren, ein Muster, das bei Video-Streaming, Datenbank-Indizes oder Log-Dateien im Browser entscheidend ist.

9. Origin Private File System im Überblick

Die folgende Tabelle fasst zusammen, wann das Origin Private File System die richtige Wahl gegenüber verwandten Browser-APIs ist. Die Auswahl orientiert sich an Datenmenge, Zugriffsmuster und ob eine Nutzerinteraktion mit echten Dateien nötig ist.

Anforderung Unpassende Wahl Empfehlung Begründung
Große Binärdaten, hoher Durchsatz IndexedDB Blobs Origin Private File System Sync Access Handles ohne Transaktions-Overhead
Nutzer öffnet lokale Datei Origin Private File System File System Access API Berechtigungsdialog und echter Dateisystem-Pfad nötig
Kleine strukturierte Objekte Origin Private File System pro Objekt IndexedDB Indizierung und Query-Engine bereits eingebaut
SQL-Datenbank im Browser IndexedDB als Objekt-Store SQLite Wasm über Origin Private File System Echte ACID-Transaktionen und SQL-Syntax
Zugriff vom Hauptthread ohne Worker Sync Access Handle createWritable() Sync Access Handles nur in Dedicated Workern erlaubt

Die Kernaussage der Tabelle: Das Origin Private File System ist kein Ersatz für IndexedDB oder die File System Access API, sondern eine Ergänzung für genau die Fälle, in denen Datei-Semantik, hoher Durchsatz und synchroner Zugriff im Worker gebraucht werden. Wer diese drei Kriterien nicht braucht, fährt mit IndexedDB oft einfacher und mit weniger Architektur-Aufwand.

Mironsoft

JavaScript-Architektur, Web Storage und Performance-Engineering

Offline-fähige Anwendungen mit echter Dateisystem-Performance?

Wir konzipieren Storage-Architekturen mit dem Origin Private File System, von Worker-basierten Sync Access Handles bis zu SQLite-Wasm-Integrationen für datenintensive Web-Anwendungen.

Storage-Architektur

Analyse, ob Origin Private File System, IndexedDB oder Cache Storage die richtige Wahl ist

Worker-Integration

Sync Access Handles, Message-Protokolle und Locking-Strategien sauber implementieren

Performance-Audit

Benchmarks und Migrationsstrategie von IndexedDB auf das Origin Private File System

10. Zusammenfassung

Das Origin Private File System bringt echte Dateisystem-Semantik in den Browser, isoliert pro Origin und ohne Berechtigungsdialog für den Nutzer. Der entscheidende Unterschied zu IndexedDB liegt in den synchronen Sync Access Handles, die ausschließlich in Dedicated Workern verfügbar sind und dort direkte, unbufferte Lese- und Schreibzugriffe ohne Transaktions-Overhead erlauben. Für Wasm-Portierungen wie SQLite, für Video- und Bildbearbeitung sowie für alle Anwendungsfälle mit hohem I/O-Durchsatz ist das Origin Private File System aktuell die schnellste verfügbare Browser-Speicheroption.

Gleichzeitig ist das Origin Private File System kein Universalersatz: Für einfache strukturierte Daten mit Indizierungsbedarf bleibt IndexedDB die einfachere Wahl, und für den Zugriff auf echte lokale Dateien des Nutzers ist die File System Access API zuständig. Wer die drei APIs bewusst nach ihrem jeweiligen Stärkeprofil einsetzt, baut Anwendungen, die sowohl performant als auch wartbar bleiben, ohne unnötige Komplexität durch die falsche Storage-Wahl.

Origin Private File System — Das Wichtigste auf einen Blick

Einstiegspunkt

navigator.storage.getDirectory() liefert das Wurzel-Handle des Origin Private File System, von dort Verzeichnisse und Dateien anlegen.

Sync Access Handle

createSyncAccessHandle() nur im Dedicated Worker, synchrones read/write ohne Event-Loop-Overhead.

Ideal für

SQLite Wasm, Bild- und Videobearbeitung, große Binärdateien mit hohem Durchsatz.

Nicht geeignet für

Zugriff auf echte lokale Nutzerdateien (File System Access API) oder einfache indizierte Objekte (IndexedDB).

11. FAQ: Origin Private File System

1Was ist das Origin Private File System genau?
Ein isolierter, vom Browser verwalteter Dateisystem-Bereich pro Origin, ohne Sichtbarkeit für den Nutzer und ohne Berechtigungsdialog.
2Unterschied zur File System Access API?
Die File System Access API greift mit Zustimmung auf echte lokale Dateien zu. OPFS ist ein privater interner Speicher ohne Dialog.
3Warum nur Worker für Sync Access Handles?
Synchrone I/O würde den Hauptthread einfrieren. In Dedicated Workern ist das unkritisch, deshalb die Beschränkung.
4Schneller als IndexedDB?
Bei großen Binärdaten oft Faktor 5 bis 15, weil kein Transaktions-Overhead anfällt. Bei kleinen indizierten Objekten bleibt IndexedDB praktischer.
5Wie viel Speicherplatz ist verfügbar?
Abhängig vom Quota-Anteil des Origins, abrufbar über navigator.storage.estimate(). persist() schützt vor automatischer Räumung.
6Sichtbar im Datei-Explorer?
Nein, vollständig intern. Nur über die Website-Daten-Löschfunktion im Browser entfernbar.
7Wie läuft SQLite darüber?
Ein VFS-Layer auf Basis von Sync Access Handles legt die Datenbankdatei physisch im Origin Private File System ab.
8Zwei gleichzeitige Zugriffe auf dieselbe Datei?
Der zweite Aufruf schlägt mit NoModificationAllowedError fehl. Eine Warteschlange oder Web Locks lösen das koordiniert.
9Welche Browser unterstützen es?
Chrome/Edge ab 108, Firefox ab 111, Safari ab 17. Feature-Detection mit IndexedDB-Fallback empfohlen.
10Muss ich Handles manuell schließen?
Ja, mit close() in try/finally. Sonst bleibt die Datei bis zum Worker-Ende gesperrt.