DuckDB 2.0: cómo migrar desde 1.4 y 1.5 sin romper tu base de datos ni tu código Python

DuckDB 2.0.0 LTS salió el 21 de octubre de 2026, y lo primero que debes saber antes de actualizar es que instalar la nueva versión no convierte tu archivo de base de datos. Lo comprobamos: instalamos 2.0 junto a 1.4.5, abrimos con ella una base de datos real creada en 1.4, escribimos en ella y la volvimos a abrir en 1.4 sin ningún problema. El archivo solo pasa al nuevo formato de almacenamiento cuando lo migras tú, y a partir de ese momento las versiones anteriores ya no pueden abrirlo.

Esta guía cubre qué cambia, qué se rompe en Python y en SQL, cómo pasar una base de datos al nuevo formato y si conviene actualizar ya o esperar.

¿Qué es DuckDB?

DuckDB es una base de datos SQL analítica (OLAP) de código abierto que se ejecuta dentro de tu propio proceso, sin servidor que instalar, y que consulta directamente archivos Parquet, CSV, JSON y sus propios archivos .db. Tiene licencia MIT, así que es gratis, suma 42.4K estrellas en GitHub y se usa desde Python, la CLI, R, Java, Go, Rust y el navegador (Wasm).

La versión 2.0.0 (“Cinnamon Teal”) es una versión de soporte extendido (LTS) con soporte hasta, como mínimo, octubre de 2027. El equipo de DuckDB la describe como su mayor versión de funcionalidades hasta la fecha, construida con cerca de 20.000 commits desde la 1.5.

¿DuckDB vs SQLite: en qué se diferencian?

Las dos son bases de datos embebidas que guardan todo en un solo archivo, pero están pensadas para cargas distintas. SQLite está optimizada para muchas lecturas y escrituras pequeñas y transaccionales, como las de una app que guarda registros uno a uno. DuckDB almacena los datos por columnas y está optimizada para recorrer y agregar tablas grandes: sumas, agrupaciones y uniones sobre millones de filas. Una forma rápida de verlo es pensar en DuckDB como “SQLite para analítica”.

¿Qué trae de nuevo DuckDB 2.0?

Las novedades principales son:

  • Modo cliente/servidor con CONNECT. El protocolo remoto Quack llegó en la 1.5.3, en mayo. La 2.0 trae una versión pulida y una nueva sentencia CONNECT que adjunta una base de datos remota y cambia a ella en un solo paso. CONNECT también funciona contra PostgreSQL y MySQL, donde un nuevo optimizador de remote pushdown envía la consulta al servidor remoto en lugar de traer tablas completas por la red.
  • Triggers. CREATE TRIGGER con BEFORE y AFTER, FOR EACH ROW y FOR EACH STATEMENT, y tablas de transición con REFERENCING OLD/NEW TABLE. Algunas combinaciones, como BEFORE ... FOR EACH ROW, todavía no están soportadas.
  • El tipo VARIANT como ciudadano de primera clase, para datos semiestructurados como JSON, almacenados en formato columnar (“shredded”) en lugar de como texto.
  • E/S asíncrona para leer Parquet y CSV, que mantiene varias peticiones en vuelo. La mejora se nota sobre todo en almacenamiento de objetos como s3://.
  • Modo agente en la CLI. Cuando un agente de programación como Claude Code, Codex o Cursor maneja la CLI, esta cambia a tablas Markdown compactas, avisa cuando un resultado está truncado y reporta los errores en JSON. Según DuckDB, en sus propios experimentos con TPC-H esto redujo un 59 por ciento la salida que el modelo tenía que leer. Puedes forzarlo con -agent o desactivarlo con -no-agent.
  • Un nuevo parser SQL basado en PEG pasa a ser el predeterminado y reemplaza al derivado de PostgreSQL.

¿Actualizar DuckDB convierte tu archivo de base de datos?

No. Cuando DuckDB 2.0 abre una base de datos creada con una versión anterior, el archivo conserva su versión de almacenamiento y sigue siendo legible por esa versión anterior. En nuestra prueba, una base de datos creada con 1.4.5 seguía reportando storage_version: v1.0.0+ después de que 2.0 la abriera e insertara una fila, y 1.4.5 la volvió a abrir después con la nueva fila intacta.

La incompatibilidad va en el otro sentido. Todo archivo nuevo creado por 2.0 usa el formato de almacenamiento de 2.0, y las versiones anteriores a 2.0 no pueden leerlo. En nuestra prueba, 1.4.5 falló al abrir un archivo creado con 2.0 con un IO Error que indica que el archivo fue creado con una versión más nueva de DuckDB.

El riesgo real está en los entornos mixtos: si varios procesos comparten un archivo y uno de ellos, ya en 2.0, lo crea, los procesos que siguen en 1.x dejan de poder abrirlo. La guía de migración lo advierte de forma explícita: verifica que todos los procesos que tocan un archivo compartido estén en una versión compatible.

Puedes comprobar en qué formato está un archivo con:

SELECT database_name, tags FROM duckdb_databases();

¿Cómo migrar una base de datos a DuckDB 2.0?

Expórtala con la versión anterior e impórtala con la nueva. Así lo indica la guía de migración (duckdb 2.0 migration):

/older/duckdb mydata.old.db -c "EXPORT DATABASE 'tmp'"
/newer/duckdb mydata.new.db -c "IMPORT DATABASE 'tmp'"

Hicimos los mismos dos pasos desde Python (1.4.5 para exportar, 2.0.0 para importar) y pasaron todas las filas. La guía también menciona COPY FROM DATABASE como alternativa.

Si necesitas lo contrario, es decir, archivos nuevos que las versiones anteriores todavía puedan leer, fija la versión de almacenamiento de forma explícita. En la CLI:

duckdb my.db -storage-version v1.5.6 -c "CREATE TABLE t (x INT);"

En Python:

duckdb.connect("my.db", config={"storage_compatibility_version": "v1.5.0"})

El mismo ajuste está disponible como opción de configuración storage_compatibility_version o como opción STORAGE_VERSION de ATTACH.

¿Qué se rompe al usar DuckDB 2.0 con Python?

El cliente de Python es el que acumula más cambios incompatibles. Los que tienen más probabilidades de afectar a tu código son:

  • Se requiere Python 3.11 o superior. En Python 3.10, pip install duckdb instala en silencio una versión 1.x. Las builds de CPython free-threaded no están soportadas.
  • La salida Arrow y Polars sale de execute(). con.execute(q).fetch_arrow_table(), fetch_record_batch(), arrow() y pl() ya no existen. Usa una relación: con.sql(q).to_arrow_table(), con.sql(q).to_arrow_reader() o con.sql(q).pl().
  • Las relaciones ya no devuelven filas una a una. rel.fetchone(), rel.fetchmany(n), rel.execute() y rel.fetch_df_chunk() desaparecen. Usa con.execute(q) para los bucles de fetch, rel.iter_rows() para iterar y rel.materialize() para calcular y conservar el resultado.
  • Una conexión usada desde varios hilos ahora lanza un error. Una llamada mientras otro hilo usa la conexión lanza ResourceInUseException. Dale a cada hilo su propio con.cursor().
  • Los resultados abiertos bloquean la conexión. Ejecutar otra consulta mientras un resultado de execute() está a medio leer lanza ResourceInUseException hasta que lo termines de leer o llames a con.complete() o con.abort().
  • Cualquier sentencia fallida aborta la transacción. Después de con.begin(), un execute() que falla hace que la transacción se revierta al hacer commit.
  • Los strings simples en expresiones son valores, no nombres de columna. Escribe col("x") para una columna y lit("x") para texto; los nombres con punto necesitan col("t", "x").
  • write_csv y write_parquet con overwrite=False ahora lanzan IOException si el archivo ya existe, en lugar de reemplazarlo.
  • El tamaño de lote de Arrow baja por defecto de 1.000.000 a 131.072 filas; pasa batch_size si necesitas otro.

¿Qué cambia en el SQL de DuckDB 2.0?

  • Las lambdas con flecha quedan desactivadas por defecto. x -> x + 1 ahora falla con un error del binder; escribe lambda x: x + 1. Con SET lambda_syntax = 'enable_single_arrow'; puedes reactivar temporalmente la forma antigua, pero tanto el ajuste como esa sintaxis desaparecen en la 2.1.
  • La división entera y el módulo por cero lanzan un error. 1 // 0 antes devolvía NULL y ahora falla. Envuélvelo como TRY(1 // 0) o usa SET error_on_division_by_zero = false para recuperar el NULL de forma global. La división normal 1 / 0 sigue devolviendo inf.
  • Los ajustes de S3 en la URL se ignoran. s3://bucket/file.csv?s3_access_key_id=... ahora trata el ?… como parte de la clave del objeto. Usa secrets o, si lo necesitas, vuelve al comportamiento anterior con SET s3_enable_deprecated_url_parameters = true después de cargar httpfs.
  • Ajustes eliminados: custom_profiling_settings (usa tracked_metrics), enable_http_logging y http_logging_output (usa CALL enable_logging('HTTP')). profiling_mode queda obsoleto y ya no tiene efecto.
  • El nuevo parser está diseñado para ser compatible. Si una consulta que antes funcionaba ahora falla, INSTALL AND LOAD legacy_parser; SET enable_legacy_parser = true; vuelve al parser anterior mientras lo reportas.

¿Cómo instalar DuckDB 2.0?

En Python, pip install duckdb instala la 2.0.0 desde el 21 de octubre de 2026 (lo comprobamos), siempre que uses Python 3.11 o superior. Para actualizar un entorno existente, usa pip install --upgrade duckdb.

Para la CLI, los instaladores oficiales son:

curl https://install.duckdb.org | bash      # macOS / Linux
winget install DuckDB.cli                   # Windows

Al momento de publicar esta nota, la página de instalación de DuckDB todavía mostraba la 1.5.6 como versión “current”, así que ejecuta duckdb --version después de instalar para confirmar que tienes la 2.0.0. El anuncio indicaba que los clientes de Go, R y Java, y algunas extensiones, llegarían en los días siguientes, y los paquetes de Node.js aún no se habían actualizado cuando lo revisamos.

¿Cómo funciona DuckDB como servidor?

Cualquier proceso de DuckDB puede servir sus bases de datos mediante Quack (duckdb client server), y cualquier otro DuckDB puede conectarse a él. Según el anuncio, en el servidor:

CALL quack_serve(token = 'my_token');

Y en el cliente:

ATTACH 'quack:localhost' AS qk (TOKEN 'my_token');
CONNECT qk;
SELECT * FROM events;

Desde la CLI, duckdb -serve inicia un servidor y duckdb -connect se conecta a él.

Por defecto, el servidor solo escucha en localhost. Para aceptar conexiones desde otras máquinas, la vía documentada es mantenerlo en localhost detrás de un proxy inverso que termine TLS; la opción allow_other_hostname, que lo expone directamente, está pensada solo para pruebas. (Esta parte no pudimos ejecutarla: quack_serve instala la extensión quack la primera vez que se usa, y nuestro entorno de pruebas bloquea la descarga de extensiones. La sintaxis de arriba es la del anuncio oficial.)

¿Conviene migrar a DuckDB 2.0 ya o esperar?

Depende de la versión que uses y de lo crítica que sea la carga:

  • Si estás en 1.4 LTS: su soporte termina el 17 de noviembre de 2026. Necesitas un plan en cualquier caso, ya sea la 2.0 o la 1.5 como puente.
  • Si estás en 1.5: su soporte se extendió hasta marzo de 2027, así que no hay prisa.
  • Cargas críticas: el propio equipo de DuckDB recomienda esperar al primer parche, previsto para noviembre, y probar en un sistema espejo que replique producción antes de cambiar.
  • Notebooks, scripts y herramientas de un solo proceso: actualizar es de bajo riesgo, porque tus archivos existentes siguen siendo legibles por 1.x hasta que los conviertas a propósito.

¿Y tú? ¿Qué versión de DuckDB tienes hoy en producción?

¿Cuándo vas a migrar a DuckDB 2.0?
  • Ya migré
  • Esta semana
  • Después del parche de noviembre
  • Prefiero otra opción (cuéntanos cuál)
0 votantes

Comenta abajo o, si este artículo te llegó por correo, responde directamente al email: tu respuesta se publica aquí.

Relacionado: La licencia MIT no es una garantía de gobernanza: qué te asegura realmente la DuckDB Foundation