IndexedDB en la práctica: almacenamiento de archivos grandes y arquitectura offline en el navegador
¿Por qué IndexedDB?
Las opciones de almacenamiento del navegador tienen límites claros cada una:
| Opción | Capacidad | Tipos de datos | API síncrona | Caso de uso |
|---|---|---|---|---|
| Cookie | ~4KB | String | ✅ | Identificadores de sesión |
| localStorage | ~5MB | String | ✅ | Configuraciones simples |
| sessionStorage | ~5MB | String | ✅ | Estado temporal |
| IndexedDB | Cientos de MB–GB | Cualquier dato estructurado | ❌ Async | Archivos grandes, apps offline |
Para sitios de herramientas que necesitan guardar en el navegador intermedios de procesamiento de PDF, módulos WASM o el historial de cargas de los usuarios, IndexedDB es la única opción viable.
Conceptos centrales
Base de datos → Object Store → Registro
Database: "toolsku-cache"
├── ObjectStore: "wasm-modules" (key: moduleName)
├── ObjectStore: "file-cache" (key: fileHash, index: timestamp)
└── ObjectStore: "user-preferences" (key: settingKey)
Transacciones y concurrencia
Las transacciones de IndexedDB se auto-confirman, y solo se permite una transacción de lectura/escritura por Object Store a la vez:
const tx = db.transaction(['file-cache'], 'readwrite');
const store = tx.objectStore('file-cache');
await store.put({ hash: 'abc123', data: arrayBuffer, timestamp: Date.now() });
await tx.done; // Wait for transaction to complete
IndexedDB en ToolsKu
Caché de módulos WASM
ffmpeg.wasm tiene unos 30 MB y tarda de 3 a 5 segundos en cargar cada vez. Tras guardarlo en caché en IndexedDB, las visitas siguientes son casi instantáneas:
async function getWasmModule(name: string): Promise<ArrayBuffer> {
const cached = await idb.get('wasm-modules', name);
if (cached) return cached;
const response = await fetch(`/wasm/${name}.wasm`);
const buffer = await response.arrayBuffer();
await idb.put('wasm-modules', buffer, name);
return buffer;
}
Almacenamiento en fragmentos para archivos grandes
Guardar archivos de más de 50 MB en IndexedDB de una sola vez no es ideal. Una estrategia de fragmentación:
File (200MB) → split into 4MB chunks → store each in IndexedDB
key: "file:{hash}:chunk:{index}"
Read in order and concatenate → restore full file
Migración de versiones
Cuando cambia el esquema de la base de datos, la migración se maneja en onupgradeneeded:
const request = indexedDB.open('toolsku-cache', 2); // version 2
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (event.oldVersion < 2) {
db.createObjectStore('processing-history', { keyPath: 'id' });
}
};
Práctica recomendada: agrega ObjectStores únicamente — nunca los elimines. Incrementa el número de versión para activar la migración y evita borrar los datos de los usuarios.
IndexedDB vs OPFS
| Característica | IndexedDB | OPFS (Origin Private File System) |
|---|---|---|
| Madurez de API | Amplio soporte | Chrome 86+ / Safari 15.2+ |
| Modelo de lectura/escritura | Almacén clave-valor | Sistema de archivos real |
| Rendimiento | Moderado | Mayor (especialmente acceso síncrono) |
| Mejor para | Caché estructurado | E/S de archivos grandes |
ToolsKu usa principalmente IndexedDB, con OPFS como optimización de rendimiento en Chrome.
Resumen
IndexedDB es infraestructura esencial para herramientas de navegador offline-first. Un buen diseño de ObjectStores, el caché de WASM y las estrategias de almacenamiento en fragmentos permiten que ToolsKu siga respondiendo incluso en redes lentas.
Prueba estas herramientas que se ejecutan en tu navegador — no requieren registro →