Saltar al contenido
Mark-Co Digital
Supabase

Escrituras concurrentes en SQLite: BEGIN CONCURRENT en Turso 0.8

SQLite permite un solo escritor a la vez. Turso Database propone MVCC y BEGIN CONCURRENT para que varias transacciones escriban en paralelo. Cómo funciona, cómo se usa y en qué estado está.

9 min de lectura Investigado y publicado con Claude

Portada de la serie Turso en español, parte 7: Escrituras concurrentes, lo nuevo de Turso 0.8, sobre fondo azul noche con ilustración de base de datos
En este artículo
  1. El problema: un solo escritor
  2. Cómo lo resuelve Turso: MVCC inspirado en Hekaton
  3. Cómo se usa
  4. Los números que publica Turso
  5. El estado real: estable, experimental o preview
  6. Qué significa para tu proyecto
  7. Preguntas frecuentes
  8. Cómo seguimos
  9. Fuentes

SQLite clásico deja escribir a una sola transacción por vez, y eso es lo que suele empujar a los equipos hacia PostgreSQL cuando la app crece. Turso Database, la reescritura de SQLite en Rust, resuelve ese cuello de botella con MVCC (control de concurrencia multiversión) y la instrucción BEGIN CONCURRENT, que en la versión 0.8, publicada a fines de septiembre de 2026, figura como estable en el anuncio oficial. Hay matices de estado que conviene conocer antes de usarlo en producción, y los repasamos acá.

Seguimos con la serie "Turso en español" de Mark-Co Digital. Si te perdiste la diferencia entre Turso Database, libSQL y Turso Cloud, está explicada en qué es Turso.

El problema: un solo escritor#

En el anuncio de Turso 0.8, Pekka Enberg (CTO de Turso) lo resume así: el modelo de un solo escritor de SQLite implica mayor latencia de cola en las transacciones y un techo de throughput cuando hay escrituras concurrentes. En la práctica, si diez procesos quieren escribir al mismo tiempo, nueve esperan. Quien trabajó con SQLite en producción conoce el error SQLITE_BUSY, que Turso menciona explícitamente en su post de octubre de 2025 sobre este tema.

libSQL, el fork de SQLite que mantiene Turso, hereda esa misma limitación según su propio README. Por eso esta función es del motor nuevo, Turso Database, y no de libSQL.

Cómo lo resuelve Turso: MVCC inspirado en Hekaton#

Según el post técnico de Turso sobre el tema (octubre de 2025), el diseño de MVCC está inspirado en Hekaton y se apoya en tres ideas:

  • Aislamiento por snapshot: cada transacción ve una foto consistente de la base.
  • Detección de conflictos por fila al confirmar: dos transacciones que tocan filas distintas pueden confirmar las dos; si tocan la misma fila, una recibe un error de conflicto.
  • Log lógico: los cambios se registran en un log que después se vuelca (checkpoint) al archivo de la base a través del WAL.

Group commit, la pieza que llegó en 0.8#

La otra novedad de 0.8 es el group commit. En su análisis del 29 de septiembre de 2026, Pere Diaz Bou explica que en la versión 0.7 cada transacción pagaba su propio fsync (la escritura forzada a disco), y los escritores concurrentes terminaban haciendo fila detrás de esas descargas. Con group commit, las transacciones que confirman casi al mismo tiempo comparten un solo fsync. Ese cambio es el que, según el post, mejoró de forma drástica la latencia de cola.

Cómo se usa#

La documentación de concurrent writes lo plantea en dos pasos. Primero, activar el modo MVCC:

PRAGMA journal_mode = 'mvcc';

Después, abrir transacciones con BEGIN CONCURRENT en lugar de BEGIN:

BEGIN CONCURRENT;
-- tus escrituras acá
COMMIT;

El patrón de reintento es obligatorio#

La regla clave: cuando dos escrituras se superponen, el motor devuelve un error de conflicto y la aplicación tiene que reintentar. No es un detalle opcional. La documentación incluye este ejemplo en JavaScript, con 16 workers insertando en paralelo (es un fragmento: omite los imports del original):

const DB_PATH = join(mkdtempSync(join(tmpdir(), "turso-mvcc-")), "hits.db");

function isRetryable(err) {
  const msg = (err?.message ?? "").toLowerCase();
  return msg.includes("conflict") || msg.includes("busy");
}

async function writeWorker() {
  const val = Math.floor(Math.random() * 100) + 1;
  const db = await connect(DB_PATH);
  try {
    await db.exec("PRAGMA journal_mode = 'mvcc'");
    while (true) {
      await db.exec("BEGIN CONCURRENT");
      try {
        await db.exec(`INSERT INTO hits VALUES (${val})`);
        await db.exec("COMMIT");
        return val;
      } catch (err) {
        // si falla, deshacemos y reintentamos solo si es un conflicto
        try { await db.exec("ROLLBACK"); } catch (_) {}
        if (!isRetryable(err)) throw err;
        await new Promise((r) => setImmediate(r));
      }
    }
  } finally {
    await db.close();
  }
}

const setup = await connect(DB_PATH);
await setup.exec("PRAGMA journal_mode = 'mvcc'");
await setup.exec("CREATE TABLE hits (val INTEGER)");
await setup.close();

await Promise.all(Array.from({ length: 16 }, () => writeWorker()));

La clave: ROLLBACK, distinguir conflictos de errores reales y reintentar. Jeff Olson profundiza en estos patrones en su guía Concurrent Writes in Practice, publicada en agosto de 2026 en el blog de Turso.

Ajustes finos#

La página de pragmas documenta dos parámetros para afinar el comportamiento de MVCC: PRAGMA mvcc_checkpoint_threshold y PRAGMA mvcc_gc_threshold (ambos con 1000 como valor de ejemplo). Conviene empezar con los valores por defecto.

En Turso Cloud#

Las escrituras concurrentes llegaron a Turso Cloud como early preview el 3 de agosto de 2026, según el anuncio de Glauber Costa (CEO de Turso). Se activan en el dashboard, en Settings → General, y después se crea una base con el motor nuevo:

turso db create --tursodb <name>

Ojo: en Turso Cloud el pragma journal_mode no está soportado según la página de limitaciones; por eso la activación pasa por el dashboard. El mismo anuncio muestra cómo pedir una transacción concurrente desde TypeScript:

const insertUser = conn.transactionAsync(async (tx, name) => {
  await tx.run("INSERT INTO users (name) VALUES (?)", [name]);
});
await insertUser.concurrent("Alice");

Y desde Python, con el driver remoto:

conn = turso_serverless.connect(
    os.environ["TURSO_DATABASE_URL"],
    auth_token=os.environ["TURSO_AUTH_TOKEN"],
    isolation_level="CONCURRENT",
)

Los números que publica Turso#

Según los benchmarks publicados por Turso en el anuncio de 0.8:

Métrica Turso 0.8 SQLite
Latencia p99.9 con 32 conexiones 2,4 ms 1,2 s
Transacciones por segundo con 64 conexiones 9.500 1.370

Son cifras del fabricante, en su escenario de prueba (en marzo de 2026, el reporte del primer año de Glauber Costa hablaba de "hasta 4x" más rápido que SQLite). Sirven para entender el orden de magnitud: medí con tu carga real.

El estado real: estable, experimental o preview#

Acá las fuentes oficiales no dicen lo mismo, y es mejor saberlo:

  • Octubre de 2025: Turso lo presentaba como "early technology preview", sin soporte de CREATE INDEX en ese momento.
  • Julio de 2026 (0.7): varias piezas de escritura concurrente aparecen como Stable, incluidas Encrypted MVCC y MVCC Autoincrement; los "Passive Checkpoints" siguen como experimentales.
  • Septiembre de 2026 (0.8): el anuncio marca BEGIN CONCURRENT y MVCC como Stable.
  • Hoy, en la documentación: la página de pragmas todavía habla de un modo de journal MVCC "experimental".
  • En Turso Cloud: el último anuncio que encontramos lo describe como early preview.

Y un contexto general: Turso Database sigue siendo pre-1.0, y su README recomienda mantener backups independientes.

Incompatibilidades documentadas#

  • CDC: la captura de cambios no se puede usar con MVCC en la misma conexión.
  • WAL multiproceso: tampoco es compatible con MVCC.

Si dependés de CDC, esto pesa en la decisión.

Qué significa para tu proyecto#

Para un desarrollador, la pregunta es simple: ¿tu app tiene varios procesos o requests escribiendo en la misma base a la vez? Si la respuesta es no (un blog, un sitio institucional, una app con pocas escrituras), SQLite clásico o libSQL siguen funcionando bien y no necesitás nada de esto.

Si la respuesta es sí, por ejemplo un sistema de pedidos con picos, un backend que registra eventos de muchos usuarios o agentes de IA escribiendo estado en paralelo, BEGIN CONCURRENT abre la puerta a quedarte en el mundo SQLite más tiempo. Lo que cambia en el código:

  1. Activar MVCC (o la opción del dashboard en Cloud).
  2. Envolver las escrituras en BEGIN CONCURRENT.
  3. Implementar reintentos con criterio, idealmente en una sola función reutilizable.
  4. Revisar que no dependas de CDC ni de acceso multiproceso.

Para el dueño de una pyme: menos motivos para migrar a un servidor de base de datos más caro solo por concurrencia, a cambio de adoptar tecnología más nueva. Si tu caso es multi-tenant, recordá que repartir clientes en bases separadas (lo vimos acá) también reduce la competencia entre escritores.

Preguntas frecuentes#

¿BEGIN CONCURRENT funciona en libSQL o en SQLite estándar?#

No. Es una función de Turso Database, el motor reescrito en Rust. libSQL y SQLite mantienen el modelo de un solo escritor.

¿Qué hago si mi transacción recibe un error de conflicto?#

Hacer ROLLBACK y reintentar. Es el comportamiento esperado de MVCC con detección de conflictos al confirmar, no una falla: la documentación indica que la aplicación debe reintentar.

¿Puedo seguir usando la captura de cambios (CDC) si activo MVCC?#

No en la misma conexión, según la documentación de CDC. Tenés que elegir entre los dos o separar responsabilidades.

¿Los benchmarks de 500x aplican a mi app?#

Son mediciones de Turso en su propio escenario de 32 y 64 conexiones. Indican el tipo de mejora posible bajo mucha concurrencia, pero tu resultado depende de tu carga, tu esquema y cuántos conflictos generen tus transacciones.

Cómo seguimos#

Si tu backend está chocando con el límite de escritura de SQLite y estás evaluando alternativas, en Mark-Co Digital te ayudamos a diseñar e implementar el backend y la base de datos adecuados, incluidas opciones como Turso y Supabase. Conocé nuestro servicio de desarrollo backend o escribinos.

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