Uživatel otevře vaši aplikaci v metru, v letadle, na chatě bez signálu — a vidí spinner. Nebo prázdnou obrazovku. Nebo chybovou hlášku. V roce 2026 je tohle neakceptovatelné. Offline-first není luxus — je to základ dobré mobilní zkušenosti. A překvapivě, většina týmů to pořád dělá špatně.
Statistiky jsou jednoznačné: průměrný uživatel stráví 11 % času bez stabilního připojení k internetu. Ne proto, že by žil na vesnici — ale proto, že jezdí metrem, cestuje letadlem, prochází betonovými budovami s mizerným signálem. A v těch momentech vaše aplikace buď funguje, nebo ji uživatel nahradí jinou, která funguje.
Offline-first neznamená „aplikace nějak přežije bez internetu." Znamená to, že lokální data jsou primární zdroj pravdy a síť je mechanismus synchronizace. Tohle je fundamentální architektonický posun — ne feature, kterou přilepíte na konec.
Pro business aplikace (field service, logistika, inspekce, retail) je offline podpora kritická. Technik v terénu musí zadat data, i když nemá signál. Řidič musí potvrdit doručení v podzemní garáži. Inspektor musí vyfotit závadu v suterénu. Pokud tohle vaše aplikace neumí, máte problém.
Pro PWA a webové aplikace jsou Service Workers klíčová technologie. Service Worker je JavaScript soubor, který běží na pozadí v prohlížeči, nezávisle na hlavní stránce. Funguje jako proxy mezi aplikací a sítí — zachytává HTTP requesty a rozhoduje, jestli je obslouží z cache, ze sítě, nebo kombinací obojího.
// sw.js — registrace Service Workeru
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'))
);
});
Klíčový koncept: Service Worker přežívá zavření tabu. Jednou nainstalovaný zůstává aktivní a může obsluhovat requesty, i když je uživatel offline. To je zásadní rozdíl oproti obyčejnému HTTP cachování — máte nad ním plnou programatickou kontrolu.
Cache API řeší statické assety. Ale co dynamická data — objednávky, formuláře, produktové katalogy? Tady máte dvě hlavní volby.
Nativní browser API. Asynchronní, transakční NoSQL databáze přímo v prohlížeči. Ideální pro PWA. Kapacita v řádu stovek MB. Přístup přes strukturované klíče a indexy.
Plnohodnotná SQL databáze. Pro nativní aplikace (React Native, Flutter, Swift, Kotlin) — přímý přístup. Pro web přes sql.js nebo OPFS. Silné v relačních datech a komplexních dotazech.
Kdy co použít? Pro PWA je IndexedDB přirozená volba — je v prohlížeči, nepotřebuje WASM runtime a má slušnou výkonnost pro většinu use cases. Pro nativní mobilní aplikace je SQLite jasná volba — je rychlejší, má lepší podpora pro transakce a komplexní dotazy, a je to de facto standard v mobilním světě.
// IndexedDB — uložení offline záznamu
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()
});
}
Důležitý detail: nikdy nespoléhejte na localStorage pro offline data. Limit 5 MB, synchronní API (blokuje main thread) a žádná podpora pro indexy nebo transakce. localStorage je pro user preferences, ne pro business data.
Nejsložitější část offline-first architektury není ukládání dat — je to jejich synchronizace zpět na server, když se připojení obnoví. Existují dva fundamentální přístupy.
Uživatel provede akci, aplikace ji okamžitě potvrdí a zápis do lokální databáze. Synchronizace proběhne na pozadí, jakmile je dostupná síť. Pokud vznikne konflikt, řeší se zpětně — buď automaticky (last-write-wins, merge), nebo s uživatelským potvrzením.
Výhody: okamžitá odezva, funguje bez sítě, lepší UX. Nevýhody: konflikty, eventual consistency, složitější error handling. Použití: field service aplikace, poznámky, formuláře, ToDo listy, chat.
Uživatel provede akci, aplikace čeká na potvrzení serveru a teprve pak aktualizuje UI. Offline queue ukládá operace pro pozdější odeslání, ale neprezentuje je jako potvrzené.
Výhody: konzistence, žádné konflikty, jednodušší implementace. Nevýhody: pomalejší UX, závislost na síti pro potvrzení. Použití: finanční transakce, objednávky, medicínské záznamy — cokoliv, kde eventual consistency není akceptovatelná.
// Optimistic sync — offline queue s 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);
}
}
Manuální polling a online/offline eventy jsou fragile. Background Sync API je browser API, které řeší synchronizaci elegantně: zaregistrujete sync event v Service Workeru a prohlížeč ho spustí, jakmile má stabilní připojení — i když uživatel aplikaci zavřel.
// Registrace Background Sync z hlavní aplikace
async function scheduleSync() {
const registration = await navigator.serviceWorker.ready;
await registration.sync.register('sync-inspections');
}
// Service Worker — obsluha sync eventu
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);
}
}
}
Důležité omezení: Background Sync API má zatím plnou podporu pouze v Chromium prohlížečích. Safari podpora je omezená. Pro nativní aplikace používejte platformní ekvivalenty — WorkManager (Android) nebo BGTaskScheduler (iOS).
Výběr správné cache strategie zásadně ovlivňuje výkon i offline chování aplikace. Neexistuje jedna správná strategie — různý typ obsahu vyžaduje různý přístup.
// Stale-While-Revalidate v Service Workeru
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;
})
);
}
});
V praxi kombinujete strategie podle typu obsahu. App shell je Cache First, API endpointy jsou Stale-While-Revalidate nebo Network First, a autentizace je Network Only. Klíčové je mít toto explicitně definované v architektonickém dokumentu, ne ad hoc v kódu.
Jak to celé skládáme dohromady? Typická architektura offline-first mobilní aplikace v produkci má tyto vrstvy:
Kritický detail, který většina týmů podcení: conflict resolution. Co se stane, když dva uživatelé editují stejný záznam offline? Last-write-wins je nejjednodušší, ale ne vždy správný. Pro komplexní scénáře potřebujete CRDT (Conflict-free Replicated Data Types) nebo field-level merge s uživatelským potvrzením.
V CORE SYSTEMS dodáváme offline-first mobilní aplikace pro field service, logistiku a inspekční procesy — tedy přesně ty scénáře, kde spolehlivý offline režim není nice-to-have, ale hard requirement.
Náš přístup začíná data flow analýzou: které entity musí být dostupné offline, jaký je expected objem dat, jaké operace se provádějí bez sítě a jaká je tolerance ke konfliktům. Na základě toho navrhujeme sync strategii — většinou kombinujeme optimistic sync pro vytváření nových záznamů s pessimistic přístupem pro editace kritických dat.
Technologicky sáhneme po React Native + WatermelonDB pro nativní aplikace nebo PWA + IndexedDB + Workbox pro webové řešení. Workbox od Googlu je production-grade knihovna pro Service Worker strategie — řeší precaching, runtime caching i Background Sync s minimem boilerplate kódu.
Každá offline-first aplikace, kterou dodáváme, má: sync status indikátor v UI (uživatel vždy ví, jestli je online/offline a kolik operací čeká na sync), conflict resolution UI pro edge cases, automated sync testing v CI/CD pipeline a monitoring dashboard pro sledování sync health v produkci.
Offline podporu nemůžete přidat na konec vývojového cyklu. Je to architektonické rozhodnutí, které ovlivňuje datový model, sync logiku, UX flow i backend API design. Čím dříve ho uděláte, tím levněji vás vyjde.
Dobrá zpráva: v roce 2026 máme vyspělé nástroje — Service Workers, IndexedDB, Background Sync API, WatermelonDB, Workbox, PowerSync. Technologie není blokátor. Blokátor je architektonické myšlení, které stále předpokládá, že internet je vždy k dispozici. Není.