Ein Benutzer öffnet Ihre App in der U-Bahn, im Flugzeug, in einer Hütte ohne Signal — und sieht einen Spinner. Oder einen leeren Bildschirm. Oder eine Fehlermeldung. Im Jahr 2026 ist das inakzeptabel. Offline-first ist kein Luxus — es ist die Grundlage einer guten mobilen Erfahrung. Und überraschenderweise machen es die meisten Teams immer noch falsch.
Warum Offline wichtig ist¶
Die Statistiken sind eindeutig: Der durchschnittliche Nutzer verbringt 11 % seiner Zeit ohne stabile Internetverbindung. Nicht weil er in ländlichen Gebieten lebt — sondern weil er U-Bahn fährt, mit dem Flugzeug reist, durch Betongebäude mit schlechtem Signal geht. Und in diesen Momenten funktioniert Ihre App entweder, oder der Nutzer ersetzt sie durch eine, die funktioniert.
Offline-first bedeutet nicht „die App überlebt irgendwie ohne Internet.” Es bedeutet, dass lokale Daten die primäre Quelle der Wahrheit sind und das Netzwerk ein Synchronisationsmechanismus ist. Dies ist ein fundamentaler architektonischer Wandel — kein Feature, das Sie am Ende anhängen.
Für Business-Anwendungen (Field Service, Logistik, Inspektionen, Einzelhandel) ist Offline-Unterstützung kritisch. Ein Techniker im Feld muss Daten eingeben können, auch ohne Signal. Ein Fahrer muss die Lieferung in einer Tiefgarage bestätigen können. Ein Inspektor muss einen Defekt im Keller fotografieren können. Wenn Ihre App das nicht kann, haben Sie ein Problem.
Service Workers: Die Grundlage des Offline-Webs¶
Für PWAs und Webanwendungen sind Service Workers die Schlüsseltechnologie. Ein Service Worker ist eine JavaScript-Datei, die im Hintergrund im Browser läuft, unabhängig von der Hauptseite. Er fungiert als Proxy zwischen der Anwendung und dem Netzwerk — fängt HTTP-Anfragen ab und entscheidet, ob sie aus dem Cache, dem Netzwerk oder einer Kombination beider bedient werden.
// sw.js — Service Worker registration
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('app-shell-v2').then((cache) => {
return cache.addAll([
'/',
'/css/app.css',
'/js/app.js',
'/offline.html'
]);
})
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((cached) => cached || fetch(event.request))
.catch(() => caches.match('/offline.html'))
);
});
Schlüsselkonzept: Der Service Worker überlebt das Schließen des Tabs. Einmal installiert, bleibt er aktiv und kann Anfragen bedienen, auch wenn der Benutzer offline ist. Dies ist ein entscheidender Unterschied zum regulären HTTP-Caching — Sie haben die volle programmatische Kontrolle darüber.
IndexedDB vs SQLite: Wo Offline-Daten speichern¶
Die Cache API behandelt statische Assets. Aber was ist mit dynamischen Daten — Bestellungen, Formularen, Produktkatalogen? Hier haben Sie zwei Hauptoptionen.
IndexedDB¶
Native Browser-API. Asynchrone, transaktionale NoSQL-Datenbank direkt im Browser. Ideal für PWAs. Kapazität im Bereich von Hunderten MB. Zugriff über strukturierte Schlüssel und Indizes.
SQLite (WASM / nativ)¶
Vollwertige SQL-Datenbank. Für native Anwendungen (React Native, Flutter, Swift, Kotlin) — direkter Zugriff. Für Web über sql.js oder OPFS. Stark bei relationalen Daten und komplexen Abfragen.
Wann was verwenden? Für PWAs ist IndexedDB die natürliche Wahl — sie ist im Browser integriert, benötigt keine WASM-Runtime und bietet angemessene Performance für die meisten Anwendungsfälle. Für native mobile Anwendungen ist SQLite die klare Wahl — sie ist schneller, hat bessere Unterstützung für Transaktionen und komplexe Abfragen und ist der De-facto-Standard in der mobilen Welt.
// IndexedDB — saving offline record
async function saveOfflineRecord(record) {
const db = await openDB('fieldwork', 1, {
upgrade(db) {
const store = db.createObjectStore('inspections', {
keyPath: 'id'
});
store.createIndex('synced', 'synced');
store.createIndex('timestamp', 'timestamp');
}
});
await db.put('inspections', {
...record,
id: crypto.randomUUID(),
synced: false,
timestamp: Date.now()
});
}
Wichtiges Detail: Verlassen Sie sich niemals auf localStorage für Offline-Daten. 5 MB Limit, synchrone API (blockiert den Main Thread) und keine Unterstützung für Indizes oder Transaktionen. localStorage ist für Benutzereinstellungen, nicht für Geschäftsdaten.
Sync-Strategien: Optimistisch vs Pessimistisch¶
Der komplexeste Teil der Offline-First-Architektur ist nicht das Speichern von Daten — es ist die Synchronisation zurück zum Server, wenn die Verbindung wiederhergestellt wird. Es gibt zwei grundlegende Ansätze.
Optimistic Sync (Offline-First)¶
Der Benutzer führt eine Aktion aus, die App bestätigt sie sofort und schreibt in die lokale Datenbank. Die Synchronisation erfolgt im Hintergrund, sobald das Netzwerk verfügbar ist. Bei Konflikten werden diese rückwirkend gelöst — entweder automatisch (Last-Write-Wins, Merge) oder mit Benutzerbestätigung.
Vorteile: sofortige Reaktion, funktioniert ohne Netzwerk, bessere UX. Nachteile: Konflikte, Eventual Consistency, komplexeres Error Handling. Einsatz: Field-Service-Apps, Notizen, Formulare, ToDo-Listen, Chat.
Pessimistic Sync (Online-First)¶
Der Benutzer führt eine Aktion aus, die App wartet auf die Serverbestätigung und aktualisiert erst dann die UI. Die Offline-Warteschlange speichert Operationen für die spätere Übermittlung, präsentiert sie aber nicht als bestätigt.
Vorteile: Konsistenz, keine Konflikte, einfachere Implementierung. Nachteile: langsamere UX, Netzwerkabhängigkeit für Bestätigung. Einsatz: Finanztransaktionen, Bestellungen, medizinische Aufzeichnungen — alles, wo Eventual Consistency nicht akzeptabel ist.
// Optimistic sync — offline queue with retry
class SyncManager {
async enqueue(operation) {
const queue = await this.getQueue();
queue.push({
id: crypto.randomUUID(),
operation,
timestamp: Date.now(),
retries: 0,
status: 'pending'
});
await this.saveQueue(queue);
this.attemptSync();
}
async attemptSync() {
if (!navigator.onLine) return;
const queue = await this.getQueue();
for (const item of queue.filter(i => i.status === 'pending')) {
try {
await this.sendToServer(item.operation);
item.status = 'synced';
} catch (e) {
item.retries++;
if (item.retries >= 3) item.status = 'failed';
}
}
await this.saveQueue(queue);
}
}
Background Sync API¶
Manuelles Polling und Online/Offline-Events sind fragil. Die Background Sync API ist eine Browser-API, die Synchronisation elegant handhabt: Sie registrieren ein Sync-Event im Service Worker und der Browser löst es aus, sobald er eine stabile Verbindung hat — selbst wenn der Benutzer die App geschlossen hat.
// Register Background Sync from main app
async function scheduleSync() {
const registration = await navigator.serviceWorker.ready;
await registration.sync.register('sync-inspections');
}
// Service Worker — handle sync event
self.addEventListener('sync', (event) => {
if (event.tag === 'sync-inspections') {
event.waitUntil(syncPendingInspections());
}
});
async function syncPendingInspections() {
const db = await openDB('fieldwork', 1);
const pending = await db.getAllFromIndex(
'inspections', 'synced', false
);
for (const record of pending) {
const res = await fetch('/api/inspections', {
method: 'POST',
body: JSON.stringify(record)
});
if (res.ok) {
record.synced = true;
await db.put('inspections', record);
}
}
}
Wichtige Einschränkung: Die Background Sync API hat derzeit volle Unterstützung nur in Chromium-Browsern. Die Safari-Unterstützung ist begrenzt. Für native Apps verwenden Sie Plattform-Äquivalente — WorkManager (Android) oder BGTaskScheduler (iOS).
Cache-Strategien¶
Die Wahl der richtigen Cache-Strategie beeinflusst grundlegend die App-Performance und das Offline-Verhalten. Es gibt keine einzelne korrekte Strategie — verschiedene Inhaltstypen erfordern verschiedene Ansätze.
- Cache First: Immer aus dem Cache bereitstellen, Netzwerk nur für Updates verwenden. Ideal für statische Assets (CSS, JS, Fonts, Icons), die sich nur beim Deployment ändern.
- Network First: Netzwerk versuchen, bei Fehler auf Cache zurückfallen. Für API-Daten, wo Sie Aktualität wollen, aber veraltete Daten offline tolerieren.
- Stale-While-Revalidate: Sofort aus dem Cache bereitstellen und gleichzeitig den Cache im Hintergrund vom Netzwerk aktualisieren. Bester Kompromiss zwischen Geschwindigkeit und Aktualität. Ideal für Produktkataloge, Listen, Profile.
- Network Only: Kein Caching. Für Daten, die immer aktuell sein müssen — Auth-Tokens, Echtzeit-Preise, Transaktionen.
- Cache Only: Nur Cache, kein Netzwerk. Für vorgespeicherte Assets der App-Shell, Offline-Fallback-Seiten.
// Stale-While-Revalidate in Service Worker
self.addEventListener('fetch', (event) => {
if (event.request.url.includes('/api/products')) {
event.respondWith(
caches.open('api-cache').then(async (cache) => {
const cached = await cache.match(event.request);
const fetchPromise = fetch(event.request).then((res) => {
cache.put(event.request, res.clone());
return res;
});
return cached || fetchPromise;
})
);
}
});
In der Praxis kombinieren Sie Strategien basierend auf dem Inhaltstyp. Die App-Shell ist Cache First, API-Endpunkte sind Stale-While-Revalidate oder Network First, und Authentifizierung ist Network Only. Der Schlüssel liegt darin, dies explizit in der Architekturdokumentation definiert zu haben, nicht ad hoc im Code.
Reale Architektur einer Offline-First-Anwendung¶
Wie fügen wir alles zusammen? Eine typische produktionsreife Offline-First-Mobile-Anwendungsarchitektur hat diese Schichten:
- UI Layer: React Native / Flutter / PWA. Liest Daten ausschließlich aus der lokalen Datenbank. Niemals direkt vom Netzwerk.
- Local Storage Layer: SQLite (nativ) oder IndexedDB (Web). Strukturierte lokale Datenbank mit Indizes, Transaktionen und Migration-Support.
- Sync Engine: Eigenentwicklung oder bibliotheksbasiert (WatermelonDB, PouchDB, PowerSync). Handhabt bidirektionale Sync, Conflict Resolution, Retry-Logik und Delta Sync.
- Network Layer: HTTP/REST oder GraphQL mit Offline-Warteschlange. Interceptor erkennt Online/Offline-Status und routet Anfragen.
- Backend API: Serverseite mit Unterstützung für idempotente Operationen, Konflikterkennung (Vector Clocks, Timestamps) und Bulk-Sync-Endpunkte.
Kritisches Detail, das die meisten Teams unterschätzen: Conflict Resolution. Was passiert, wenn zwei Benutzer denselben Datensatz offline bearbeiten? Last-Write-Wins ist am einfachsten, aber nicht immer korrekt. Für komplexe Szenarien benötigen Sie CRDTs (Conflict-free Replicated Data Types) oder Field-Level-Merge mit Benutzerbestätigung.
Wie wir es bei CORE SYSTEMS bauen¶
Bei CORE SYSTEMS liefern wir Offline-First-Mobile-Anwendungen für Field Service, Logistik und Inspektionsprozesse — genau jene Szenarien, in denen ein zuverlässiger Offline-Modus kein Nice-to-have, sondern eine harte Anforderung ist.
Unser Ansatz beginnt mit einer Datenflussanalyse: Welche Entitäten müssen offline verfügbar sein, welches Datenvolumen wird erwartet, welche Operationen werden ohne Netzwerk durchgeführt und wie hoch ist die Toleranz für Konflikte. Darauf basierend entwerfen wir die Sync-Strategie — meist kombinieren wir optimistic Sync für das Erstellen neuer Datensätze mit einem pessimistischen Ansatz für die Bearbeitung kritischer Daten.
Technologisch greifen wir zu React Native + WatermelonDB für native Anwendungen oder PWA + IndexedDB + Workbox für Weblösungen. Workbox von Google ist eine produktionsreife Bibliothek für Service-Worker-Strategien — sie handhabt Precaching, Runtime Caching und Background Sync mit minimalem Boilerplate-Code.
Jede Offline-First-App, die wir liefern, hat: Sync-Status-Indikator in der UI (der Benutzer weiß immer, ob er online/offline ist und wie viele Operationen auf Sync warten), Conflict Resolution UI für Randfälle, automatisierte Sync-Tests in der CI/CD-Pipeline und Monitoring-Dashboard zur Überwachung der Sync-Gesundheit in der Produktion.
Fazit: Offline-First ist eine architektonische Entscheidung¶
Sie können Offline-Unterstützung nicht am Ende des Entwicklungszyklus hinzufügen. Es ist eine architektonische Entscheidung, die Datenmodell, Sync-Logik, UX-Flow und Backend-API-Design beeinflusst. Je früher Sie sie treffen, desto günstiger kommt sie Sie.
Gute Nachricht: Im Jahr 2026 haben wir ausgereifte Werkzeuge — Service Workers, IndexedDB, Background Sync API, WatermelonDB, Workbox, PowerSync. Technologie ist nicht der Blocker. Der Blocker ist architektonisches Denken, das immer noch davon ausgeht, dass Internet immer verfügbar ist. Ist es nicht.
Brauchen Sie Hilfe bei der Implementierung?
Unsere Experten helfen Ihnen bei Design, Implementierung und Betrieb. Von der Architektur bis zur Produktion.
Kontaktieren Sie uns