Saltar al contenido
Mark-Co Digital
Supabase

Apps que funcionan sin internet: offline-first con Turso Sync

Turso Sync permite que tu app lea y escriba en una base local y sincronice con Turso Cloud cuando vuelve la conexión. Cómo funcionan push, pull y los conflictos, y cuándo conviene.

8 min de lectura Investigado y publicado con Claude

Portada de la serie Turso en español, parte 8: Apps sin internet, offline-first con Turso Sync, sobre fondo azul noche con ilustración de base de datos
En este artículo
  1. Por qué importa en Argentina y Latinoamérica
  2. Cómo funciona Turso Sync
  3. El código, paso a paso
  4. Funciones avanzadas y su estado
  5. Casos reales que publica Turso
  6. Qué significa para tu proyecto
  7. Preguntas frecuentes
  8. Cómo seguimos
  9. Fuentes

Una app offline-first lee y escribe primero en una base de datos que vive en el propio dispositivo, y sincroniza con la nube cuando hay conexión. Turso Sync, lanzado en beta en octubre de 2025, hace exactamente eso: tu app trabaja contra un archivo SQLite local y, con dos operaciones (push y pull), intercambia cambios con Turso Cloud. Para equipos que trabajan en campo, en rutas o en zonas con señal intermitente, es una de las funciones más interesantes del ecosistema Turso.

Este post es parte de la serie "Turso en español" de Mark-Co Digital. Si querés el panorama general primero, pasá por qué es Turso.

Por qué importa en Argentina y Latinoamérica#

En la guía local-first de Turso, Jeff Olson lo plantea desde la experiencia de uso: las lecturas salen de una base local, así que la interfaz responde al instante, sin ida y vuelta por la red ni ruedita de carga. La página de soluciones local-first de Turso menciona casos como trabajo de campo, túneles, aviones y conectividad intermitente, y remarca que en el dispositivo hay una base de datos real, no un caché.

Pensá en situaciones conocidas:

  • Un técnico que releva instalaciones en una zona rural de la Patagonia sin señal.
  • Un vendedor que toma pedidos en ruta y pasa por tramos sin cobertura.
  • Un formulario de inspección que no puede perder datos porque se cortó el 4G.

En todos esos casos, el problema no es la velocidad: es que la app siga funcionando y que nada se pierda.

Cómo funciona Turso Sync#

Turso Sync se apoya en el motor Turso Database (la reescritura de SQLite en Rust) y en Turso Cloud. Según el anuncio de Nikita Sivukhin, los cambios locales se envían a la nube como mutaciones lógicas, lo que permite resolver conflictos con flexibilidad, y los cambios remotos se traen como páginas físicas, de modo que la réplica local termina siendo idéntica byte a byte a la remota. La documentación agrega que usa captura de cambios (CDC) lógica.

Push y pull#

  • push() manda tus cambios locales al servidor. Ante conflictos, la regla es "last push wins": gana el último que empuja.
  • pull() trae los cambios remotos y devuelve un booleano que indica si algo cambió localmente.

Qué pasa en un pull cuando hay cambios de los dos lados#

La documentación de resolución de conflictos describe una secuencia atómica:

  1. La base local vuelve al último estado sincronizado.
  2. Se aplican los cambios remotos.
  3. Tus cambios locales que todavía no subiste se vuelven a aplicar encima.

Si algún paso falla, todo se revierte. En la guía local-first, Jeff Olson suma un detalle útil: la regla por defecto es last-push-wins por fila, y con un "transform hook" podés convertir una operación como "poner el valor en 7" en "sumar 3", algo clave para contadores o stock.

El código, paso a paso#

La conexión básica en TypeScript, tal como figura en la documentación:

import { connect } from '@tursodatabase/sync';

const db = await connect({
  path: './app.db',                               // local path
  url: 'turso://...',                            // remote URL (generated with turso db show <db-name> --url)
  authToken: process.env.TURSO_AUTH_TOKEN,        // authentication token (generated with turso db tokens create <db-name>)
  // longPollTimeoutMs: 10_000,                   // optional: server waits before replying to pull
  // bootstrapIfEmpty: false,                     // set to false to avoid bootstrapping on first run
});

La URL y el token se generan con la CLI de Turso, como vimos en tu primera base en Turso en 5 minutos.

El patrón offline-first#

Por defecto, la primera vez que la app se conecta, la base local se arma (bootstrap) desde la remota, así que necesita red. Para que la app arranque sin conexión, la documentación indica usar bootstrapIfEmpty: false. Así, las escrituras locales quedan guardadas hasta que un push() funcione. Es el equivalente moderno del flag offline: true de las embedded replicas.

El ejemplo oficial completo:

import { connect } from '@tursodatabase/sync';

// bootstrapIfEmpty: false lets the app start offline without
// needing to reach the remote on first launch
const db = await connect({
  path: './local.db',
  url: process.env.TURSO_URL!,
  authToken: process.env.TURSO_AUTH_TOKEN!,
  bootstrapIfEmpty: false,
});

async function syncWhenOnline(db) {
  try {
    await db.push();
  } catch (e) {
    // No connectivity — changes are safe in the local file
    // and will sync on the next push() call
  }
}

// On app launch, pull the latest state if online
try {
  await db.pull();
} catch (e) {
  // Offline — local data is still available for reads and writes
}

// On a timer or connectivity event
await syncWhenOnline(db);

La lógica: pull al abrir, tolerar el error sin red y push con un temporizador o al volver la conexión.

No te olvides del checkpoint#

En las bases con sync, el auto-checkpoint está desactivado. La documentación advierte que, después de muchas escrituras, el WAL puede crecer bastante más que la propia base. La solución es llamar a mano:

await db.checkpoint();

Para monitorear, stats() devuelve datos como el tamaño del WAL, los bytes enviados y recibidos y la hora del último push y pull.

Funciones avanzadas y su estado#

  • Sync parcial (experimental): con la opción partialSyncExperimental, las páginas se traen bajo demanda. Se puede arrancar con un prefijo de la base o con las páginas que toca una consulta SQL que corre en el servidor; por ejemplo, solo los mensajes de un usuario. Útil cuando la base completa es grande y el dispositivo necesita una parte.
  • Servidor de sync local: tursodb ./server.db --sync-server 0.0.0.0:8080 implementa el mismo protocolo que Turso Cloud, sin autenticación, ideal para desarrollar y probar.
  • Permisos y autenticación: el anuncio de lanzamiento menciona permisos de token por tabla y operación, y soporte de JWKS con Clerk y Auth0.
  • Plataformas: hay paquetes para Node (@tursodatabase/sync), navegador (@tursodatabase/sync-wasm), React Native (@tursodatabase/sync-react-native), Python y Go.

Embedded replicas: el mecanismo anterior#

Antes de Turso Sync, la opción era usar embedded replicas con el cliente @libsql/client: copias locales de solo lectura de una base en Turso Cloud, con escrituras que van al servidor salvo que actives offline: true. Siguen documentadas, pero la propia documentación recomienda Turso Sync para proyectos nuevos y advierte no abrir el archivo local mientras se sincroniza, por riesgo de corrupción. Según la guía de Jeff Olson, en el benchmark de Turso los syncs llegan a ser hasta 312 veces más rápidos y usan unas 18 veces menos tráfico que las embedded replicas.

Casos reales que publica Turso#

  • Sample Vault: según el caso de estudio de Turso, cada usuario tiene su propia base que se sincroniza de la nube al dispositivo y llega a varios GB; el usuario más grande supera 1,2 millones de archivos de audio. Wojciech Adamek cuenta que muchos productores prefieren trabajar sin conexión.
  • Kin: su CTO, Simon Henriksen, dice en la página de clientes que eligieron Turso porque la replicación embebida y el sync no estaban disponibles en otro lado.

Qué significa para tu proyecto#

Si tu equipo o tus clientes trabajan donde la conexión falla, una app offline-first deja de ser un lujo. Antes de decidir, hacete estas preguntas:

  1. ¿Quién escribe los mismos datos? Si cada usuario edita sus propios registros, last-push-wins casi nunca molesta. Si varios editan el mismo stock, vas a necesitar diseñar la resolución (por ejemplo, con transform hooks).
  2. ¿Cuánto pesa la base que necesita cada dispositivo? Si es mucha, mirá el sync parcial, sabiendo que es experimental.
  3. ¿Cuánto vas a sincronizar por mes? Los planes de Turso Cloud tienen cuota de syncs (3 GB en Free); lo detallamos en precios de Turso.
  4. ¿Tolerás tecnología en beta? Turso Sync se lanzó en beta y no encontramos un anuncio de disponibilidad general. Planificá backups y pruebas.

Para una pyme: formularios que no pierden datos y vendedores que no dependen de la señal.

Preguntas frecuentes#

¿Mi app puede arrancar por primera vez sin conexión?#

Sí, si configurás bootstrapIfEmpty: false. Sin esa opción, el primer arranque necesita llegar a la base remota para armar la copia local.

¿Qué pasa si dos dispositivos modifican el mismo dato sin conexión?#

Por defecto, gana el último que hace push. En el pull, tus cambios pendientes se vuelven a aplicar encima de lo remoto. Si necesitás otra lógica, como sumar en lugar de pisar, Turso describe los transform hooks.

¿Puedo probar la sincronización sin una cuenta en la nube?#

Sí. El servidor de sync local (tursodb --sync-server) habla el mismo protocolo que Turso Cloud y no pide autenticación, así que sirve para desarrollo.

¿Por qué crece tanto el archivo WAL en el dispositivo?#

Porque en las bases con sync el auto-checkpoint está desactivado. Llamá a checkpoint() periódicamente, por ejemplo después de un push exitoso.

Cómo seguimos#

Si estás pensando en una app web o móvil que tiene que funcionar sin internet, en Mark-Co Digital te ayudamos a evaluar la arquitectura y a desarrollarla, desde el frontend con Next.js y React hasta el backend. También podés escribirnos para contarnos tu caso.

Fuentes#

Compartí este artículo

WhatsApp LinkedIn X

Servicios relacionados

Seguí leyendo

Contanos qué necesitás

Respondemos cada consulta con una propuesta concreta para tu proyecto.

Usamos cookies de analítica para entender cómo se usa el sitio y mejorarlo. Más info