DuckDB + Obsidian: analiza tu vault con SQL sin exportar nada
Tenía más de 800 notas en Obsidian. Tres años de journaling técnico, decisiones de arquitectura, apuntes de libros, ideas de proyectos. Todo bien organizado, con frontmatter YAML, tags consistentes, links entre notas.
Y seguía buscando con Cmd+Shift+F como si fuera 2010.
El buscador de Obsidian es bueno para encontrar una nota específica. Es inútil para responder preguntas como: ¿cuántos proyectos he apuntado en el último trimestre que no tienen ninguna nota de seguimiento? ¿Qué tecnologías aparecen más en mis journals de este año? ¿Cuántas notas de tipo "idea" no tienen ningún link interno hacia otro documento?
Esas preguntas no son búsquedas de texto. Son queries sobre datos estructurados. Y eso es exactamente lo que hace DuckDB.
La configuración de DuckDB con Obsidian que voy a enseñarte te permite tratar tu vault como una base de datos relacional — y correr SQL directamente sobre tus archivos .md.
DuckDB con Obsidian es la combinación de DuckDB — un motor SQL embebido de alto rendimiento — con un vault de Obsidian para tratar los archivos .md como filas de una base de datos consultable. A través de la extensión duckdb-obsidian, puedes ejecutar SQL directamente sobre tu frontmatter YAML, links internos y estructura de headings, sin exportar ni transformar ningún archivo.
Por qué DuckDB y no algo más "normal"
Podrías exportar todo tu vault a CSV y abrirlo en SQLite. O parsear el frontmatter con un script en Python y cargarlo en Pandas. Lo he hecho. Funciona, pero tienes que mantener ese pipeline de sincronización, gestionar el esquema cuando cambias tus propiedades, y el resultado no vive dentro de Obsidian — vive en otro sitio.
DuckDB resuelve esto de dos formas distintas según lo que necesites:
-
La extensión CLI
duckdb-obsidian— una extensión no oficial que expone una funciónobsidian_notes()que parsea tu vault en tiempo real directamente desde el CLI de DuckDB. Sin exportar nada. Sin pipeline. Lanzas DuckDB, cargas la extensión, y tu vault es una tabla. -
El plugin Obsidian
DuckDB and MotherDuck— un plugin que vive dentro de Obsidian, corre DuckDB WASM en el navegador, y te permite escribir bloques SQL en tus notas que renderizan como tablas markdown. El resultado se puede "congelar" como texto plano para que persista sin necesidad de re-ejecutar.
Son dos herramientas distintas para dos flujos distintos. Te explico ambas.
Opción 1: DuckDB CLI + extensión duckdb-obsidian
Esta es la opción para cuando quieres hacer análisis ad-hoc desde la terminal, escribir scripts, o conectar los resultados a otras herramientas.
Instalación
Primero necesitas DuckDB instalado. La forma más limpia dependiendo de tu sistema:
# macOS con Homebrew
brew install duckdb
# Windows con WinGet
winget install DuckDB.cli
# O directamente desde los binarios de duckdb.org/docs/installation
Verifica que funciona:
duckdb --version
# v1.2.2
# La extensión duckdb-obsidian es compatible con DuckDB 1.1.x y 1.2.x
Ahora descarga la extensión. Ve a github.com/puzan/duckdb-obsidian/releases y descarga el archivo que corresponde a tu versión de DuckDB y tu sistema operativo. El nombre del archivo tiene el formato obsidian.duckdb_extension.
Configuración
La extensión no está firmada por DuckDB, así que tienes que lanzar la CLI con extensiones sin firmar habilitadas:
duckdb --allow-unsigned-extensions
Dentro de la sesión, carga la extensión con la ruta absoluta al archivo que descargaste. Si el archivo viene comprimido (.duckdb_extension.gz), descomprímelo primero antes del LOAD:
LOAD 39;/ruta/absoluta/a/obsidian.duckdb_extension39;;
Si no quieres escribir esto cada vez, crea un archivo .duckdbrc en tu home. DuckDB lo ejecuta automáticamente al arrancar:
SET allow_unsigned_extensions = true;
LOAD 39;/ruta/absoluta/a/obsidian.duckdb_extension39;;
Para apuntar al vault, tienes dos opciones. La primera: navega al directorio del vault antes de lanzar DuckDB — la función obsidian_notes() sin argumentos escanea el directorio actual:
cd /Users/bezael/vault
duckdb --allow-unsigned-extensions
La segunda: pasa la ruta directamente como argumento a la función:
SELECT * FROM obsidian_notes(39;/Users/bezael/vault39;) LIMIT 5;
La única restricción es que el directorio debe contener una carpeta .obsidian — es como la extensión verifica que es un vault válido.
Esquema disponible
La función obsidian_notes() expone estas columnas sobre cada nota:
| Columna | Tipo | Contenido |
|---|---|---|
basename |
VARCHAR | Nombre del archivo sin .md |
filepath |
VARCHAR | Ruta absoluta al archivo |
first_header |
VARCHAR | Primer H1 de la nota, o NULL |
headers |
STRUCT[] | Todos los headings con su nivel |
properties |
JSON | Frontmatter YAML parseado como JSON |
internal_links |
STRUCT[] | Wikilinks con target, nombre y referencia |
Queries SQL reales sobre tu vault de Obsidian
Aquí es donde esto se vuelve útil de verdad.
Analizar la distribución de tags
¿Cuáles son los tags que más usas y cuántas notas tienen cada uno?
SELECT
tag,
count(*) AS total_notas
FROM (
SELECT unnest(
from_json(properties->39;$.tags39;, 39;["VARCHAR"]39;)
) AS tag
FROM obsidian_notes()
WHERE properties->>39;$.tags39; IS NOT NULL
)
GROUP BY tag
ORDER BY total_notas DESC
LIMIT 20;
Esto parsea el array tags del frontmatter de cada nota y te da un ranking. Tres años de vault analizados en menos de un segundo.
Encontrar notas huérfanas
Notas que nadie enlaza — las que más probablemente estés olvidando:
WITH todas_las_notas AS (
SELECT basename FROM obsidian_notes()
),
notas_referenciadas AS (
SELECT DISTINCT unnest(
list_transform(internal_links, l -> l.target)
) AS target
FROM obsidian_notes()
WHERE len(internal_links) > 0
)
SELECT basename
FROM todas_las_notas
WHERE basename NOT IN (SELECT target FROM notas_referenciadas)
ORDER BY basename;
Cuando corrí esto en mi vault por primera vez encontré 340 notas huérfanas. 340. Notas que había creado, nunca enlazado desde ningún otro sitio, y que esencialmente estaban muertas dentro del vault.
Grafo de links entre notas
Para exportar el grafo completo a CSV y procesarlo en otra herramienta:
COPY (
SELECT
basename AS origen,
unnest(list_transform(internal_links, l -> l.target)) AS destino
FROM obsidian_notes()
WHERE len(internal_links) > 0
) TO 39;/tmp/grafo-vault.csv39; (HEADER, DELIMITER 39;,39;);
Cruzar propiedades del frontmatter
Si usas frontmatter consistente (por ejemplo status, type, project), puedes hacer queries cruzadas:
SELECT
properties->>39;$.type39; AS tipo,
properties->>39;$.status39; AS estado,
count(*) AS total
FROM obsidian_notes()
WHERE properties->>39;$.type39; IS NOT NULL
GROUP BY tipo, estado
ORDER BY total DESC;
Esto responde preguntas como: ¿cuántos documentos de tipo "project" están en estado "in-progress" vs "done"?
Buscar patrones en journals
Si guardas journals diarios con una estructura de frontmatter predecible, puedes cruzarlos:
SELECT
basename,
properties->>39;$.mood39; AS mood,
properties->>39;$.energia39; AS energia
FROM obsidian_notes()
WHERE properties->>39;$.type39; = 39;journal39;
AND properties->>39;$.date39; >= 39;2026-01-0139;
ORDER BY properties->>39;$.date39; DESC;
Opción 2: Plugin DuckDB + MotherDuck dentro de Obsidian
Si prefieres no salir de Obsidian, el plugin oficial te mete DuckDB directamente en el editor.
Instalación
Abre Obsidian → Settings → Community plugins → Browse. Busca "DuckDB and MotherDuck". Instala y activa.
El plugin corre DuckDB WASM — no necesita instalación local de DuckDB, corre directamente en memoria dentro de Obsidian.
Cómo escribir queries
Crea un bloque de código con el lenguaje duckdb:
```duckdb
SELECT
o_orderpriority AS priority,
count(*) AS orders,
round(sum(o_totalprice), 2) AS revenue
FROM read_parquet('https://shell.duckdb.org/data/tpch/0_01/parquet/orders.parquet')
GROUP BY 1
ORDER BY revenue DESC
```
Cuando ejecutas la query (con el comando "Refresh query at cursor"), el resultado se renderiza como una tabla markdown directamente debajo del bloque.
La feature más útil del plugin es Freeze: convierte el resultado en texto plano markdown que persiste en la nota sin necesidad de re-ejecutar. El archivo .md queda con la query y su resultado como texto estático — lo que significa que funciona en cualquier plataforma que renderice markdown, incluyendo tu vault público en Quartz.
Limitaciones reales del plugin vs. CLI
El plugin tiene un caso de uso claro: consultas sobre datos externos o remotos (CSV, Parquet, JSON en URLs, MotherDuck) que quieres mostrar como tablas vivas dentro de tus notas.
Para consultar el vault en sí — los archivos .md, el frontmatter, los links — la extensión CLI es más potente. El plugin no expone obsidian_notes() porque DuckDB WASM no tiene acceso al sistema de archivos local de Obsidian de la misma forma.
Para análisis del vault completo: CLI. Para datos externos integrados en notas: plugin.
Cuándo usas esto en la práctica
Llevo usando este setup tres meses. Estos son los casos donde realmente lo abro:
Revisiones semanales. Tengo un script .sql que me lista todas las notas con status: in-progress que no he modificado en más de siete días. Corro el script los viernes. Lo que aparece en esa lista o lo priorizo o lo cierro.
Auditoría del vault cada dos meses. La query de notas huérfanas + la query de distribución de tags me da una foto de hacia dónde está derivando mi sistema de notas sin que me haya dado cuenta.
Análisis de proyectos. Cuando empiezo a trabajar en un cliente nuevo, tengo notas del sector o la tecnología dispersas por el vault. Una query me saca todo lo que he apuntado sobre ese dominio aunque no recuerde los nombres exactos de las notas.
Exportar datos a otras herramientas. DuckDB puede escribir directamente a CSV, Parquet, JSON. Si quiero hacer un análisis más visual en una hoja de cálculo o en una herramienta de BI, exporto el resultado de la query y lo importo. Sin copiar a mano.
Este enfoque encaja exactamente con la filosofía que aplicamos en el curso Construye con IA: tratar tus propios datos como un asset que puedes interrogar, no como un archivo que tienes que recordar dónde dejaste. Tu vault no es una colección de texto — es una base de conocimiento que merece una capa de consulta real.
Lo que puedes hacer hoy
Instala DuckDB. Descarga la extensión duckdb-obsidian. Corre la query de notas huérfanas sobre tu vault.
Eso solo ya te va a dar información que no tienes ahora mismo: qué parte de tu vault está desconectada del resto. A partir de ahí decides si quieres ir más lejos con análisis de tags, patterns en journals, o cruzar propiedades del frontmatter.
No necesitas un pipeline. No necesitas exportar nada. Lanzas DuckDB, cargas la extensión, y en un minuto estás corriendo SQL sobre años de notas.
Si quieres ver más flujos donde los datos y las herramientas de IA se conectan así de forma directa, en Dominicode Labs tenemos proyectos completos que aplican exactamente esta filosofía — tratar tu entorno de trabajo como datos consultables, no como texto disperso.
El patrón es el mismo que aplicamos cuando conectamos Claude a una fuente de datos externa: datos estructurados + una herramienta que los entiende = velocidad real. Si quieres ver cómo funciona ese loop completo desde el lado de la API, mira Claude API: Crash Course para developers con TypeScript.
FAQ
¿Necesito tener DuckDB instalado localmente para el plugin de Obsidian?
No. El plugin DuckDB and MotherDuck usa DuckDB WASM, que corre completamente en memoria dentro de Obsidian sin instalación adicional. La extensión CLI (duckdb-obsidian) sí requiere DuckDB instalado localmente porque necesita acceder al sistema de archivos.
¿La extensión duckdb-obsidian funciona con vaults grandes?
Sí, con matices. DuckDB está diseñado para procesar grandes volúmenes de datos de forma eficiente. En un vault de 2.000-3.000 notas las queries simples tardan menos de un segundo. Para vaults muy grandes (5.000+ notas) con queries que cruzan múltiples propiedades JSON, puede ser recomendable usar SET threads TO 4; dentro de la sesión para aprovechar todos los cores.
¿El frontmatter tiene que seguir algún formato específico?
Solo tiene que ser YAML válido al inicio del archivo, delimitado por ---. La extensión lo parsea como JSON en la columna properties. Anidamiento, arrays de tags, fechas — todo funciona. La única restricción es que las propiedades que quieras consultar deben existir en el frontmatter de esas notas.
¿Puedo conectar los resultados de estas queries a un agente de IA?
Sí, y es uno de los casos de uso más interesantes. DuckDB puede exportar a JSON con COPY (...) TO '/tmp/output.json' (FORMAT JSON). Ese JSON lo puedes pasar como contexto a un agente o a la API de Claude para que razone sobre el estado de tu vault. MotherDuck tiene incluso documentación oficial sobre cómo usar el vault de Obsidian como fuente de datos para agentes de IA. También puedes conectar DuckDB directamente a un servidor MCP para que el agente ejecute queries de forma autónoma — ese es el siguiente nivel de este setup. Para entender la base de cómo funciona ese patrón con la API de Claude, tienes la guía completa en Claude API: Crash Course para developers con TypeScript. Si te interesa explorar esa dirección con proyectos en producción, tenemos más en Dominicode Labs.
¿Por qué DuckDB y no SQLite para esto?
SQLite requiere que crees y mantengas el esquema manualmente. DuckDB infiere el esquema sobre la marcha: lee los archivos .md a través de la extensión, parsea el frontmatter como JSON, y expone todo como columnas consultables sin que hayas definido nada. Además, DuckDB tiene soporte nativo para arrays, structs y JSON anidado — que es exactamente el tipo de datos que tienes en el frontmatter de Obsidian. Con SQLite tendrías que escribir código de parseo adicional. Con DuckDB la extensión se encarga de todo.
Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.
