Ayer lanzamos un servicio de base de datos SQL fully managed diseñado exclusivamente para el framework web Astro. Vamos a profundizar en los detalles de implementación de Astro DB: cómo funciona, por qué lo construimos, y por qué estamos adoptando libSQL.
Cómo llegamos aquí
Astro es único por su enfoque en construir content-driven websites. El centro de esto es, por supuesto, el contenido, que es por lo que en Astro 2.0 lanzamos Content Collections. Nuestros usuarios lo amaron como una forma de gestionar su contenido local.
WordPress siempre ha sido una gran inspiración para nosotros. Una de las cosas que hace a WordPress tan especial es su base de datos integrada. No solo estás gestionando el contenido de tus artículos, estás gestionando datos, páginas, bloques, imágenes, y todo un ecosistema de plugins.
Queríamos algo así para Astro, pero rápidamente nos dimos cuenta de que habíamos llegado a los límites de hasta dónde podía llevarnos el static repo data.
Encontrando (y perdiendo) SQLite
En un esfuerzo por evolucionar Content Collections con data collections y references, nos dimos cuenta de que lo que estábamos haciendo era construir un ORM database-like desde el filesystem, y nos encontramos con varios desafíos al hacerlo. La core team member Erika propuso la idea: ¿por qué no usar simplemente una base de datos, SQLite?
Nos enamoramos de la idea de una base de datos ligera integrada en el propio Astro. SQLite era perfecto para las workloads read-heavy de la mayoría de content-driven websites.
Prototipamos la idea pero nos encontramos con algunos blockers. SQLite es una librería de C, así que necesita native add-ons para ejecutarse en Node.js. Esto está bien para desarrollo local, pero los native add-ons son difíciles de desplegar en hosts serverless y el tiempo de arranque era preocupante. Además, entornos clave como StackBlitz no podrían ejecutarlo en absoluto.
Derrotados, dejamos la idea en standby para centrarnos en otras cosas. Era primavera de 2023.
Encontrando (y enamorándonos de) libSQL
Al mismo tiempo — a medio mundo de distancia y completamente desconocido para nosotros — otro equipo estaba trabajando en este mismo problema. Ese equipo era Turso y su solución era libSQL.
libSQL es un fork de SQLite que introduce una colección de mejoras al runtime manteniendo compatibilidad con SQLite clásico. libSQL incluía un database client moderno para JavaScript/TypeScript que evitaba los native bindings y pasos de compilación que plagaban al resto del ecosistema. Incluso podía ejecutarse en StackBlitz vía WASM.
Turso también ofrecía hosting para bases de datos libSQL con un enfoque específico en el tipo de escala que necesitábamos (más sobre esto en un momento). Una visión empezaba a tomar forma para Astro DB, pero no fue hasta diciembre de 2023 que todas las piezas finalmente encajaron.
Diseñando una base de datos local the Astro Way
Astro DB te da una base de datos libSQL totalmente local en cuanto arrancas tu dev server. Con nuestro background como static-site generator, era importante que la base de datos pudiera construirse desde cero en el arranque para que en el futuro pueda potenciar un content layer donde los datos vengan de una variedad de lugares, incluyendo el filesystem.
Cuando ejecutas astro dev, Astro DB:
- Creará una base de datos vacía en
.astro/data.db - Leerá tu schema desde
db/config.ts - Poblará la base de datos desde
db/seed.ts - Tu database client ya está listo
El workflow refleja en gran medida el workflow de Content Collections que los usuarios de Astro ya aman. Importantly, la base de datos en sí (data.db) no es persistent. Se crea nueva desde cero cada vez que arrancas el dev server. Esto te da bases de datos one-off simples y reproducibles.
Astro DB reúne el web framework, el schema, el seed file, y la propia base de datos todo en una única historia cohesiva. Incluso incluimos un ORM para ti: Drizzle. Seleccionamos Drizzle porque es un ORM type-safe que te deja acercarte tanto al metal como quieras, y también es pluggable lo que nos permitió añadir nuestros propios comportamientos encima.
Yéndose remote con una base de datos hosted
Astro DB incluye una base de datos libSQL hosted a la que puedes conectarte durante el desarrollo local y en producción. Todo se gestiona por ti a través de nuestra plataforma Astro Studio. Puedes crear una nueva base de datos para tu proyecto en ~30 segundos.
Para lograr el tipo de escala que sabíamos que necesitaríamos en nuestra plataforma, nos asociamos con Turso que mantiene libSQL y opera la mayor plataforma de hosting de libSQL. Su compromiso con un modelo de “database per tenant” encajaba perfectamente con nuestra necesidad de crear cientos de miles de bases de datos, todas on demand.
También pasamos algo de tiempo el año pasado prototipando el producto D1 de Cloudflare. Nos gustó la visión del proyecto pero luchamos con la capa de abstracción añadida de workers y worker bindings cuando todo lo que necesitábamos era la base de datos. También dudábamos en construir sobre una tecnología de base de datos propietaria (D1) especialmente si significaba empaquetar esa tech dentro del propio Astro. En última instancia, encontramos que D1 no era un buen fit para nuestro use-case.
Schema migrations zero-downtime
El schema de tu base de datos se define en el archivo db/config.ts del proyecto. Cuando haces cambios a tu schema, necesitas pushearlos a tu base de datos hosted de forma que elimine el riesgo de pérdida de datos y downtime. Así que construimos astro db push
El comando push fue diseñado para balancear ease-of-use mientras sigue fomentando las best practices que funcionan en proyectos grandes de producción. En Astro DB no hay migration files que gestionar. En su lugar, cuando ejecutas push tu schema se compara automáticamente contra tu base de datos de producción hosted y cualquier cambio nuevo se aplica. Si esos cambios no se pueden añadir de forma segura o arriesgan pérdida de datos de cualquier manera, los cambios no se aplicarán.
Esto fomenta la estrategia de migración “expand and contract” en aplicaciones de Astro DB. Por supuesto, si estás haciendo desarrollo rápido y no te importa resetear tu base de datos según sea necesario, puedes ejecutar astro db push --force-reset para pushear cualquier cambio de schema que quieras, incluyendo un reset de la base de datos.
Pasamos por varias iteraciones diferentes de nuestro sistema de schema migration antes de llegar a esta versión final. En algún momento incluso tuvimos una carpeta migrations/ donde manualmente creabas y commiteabas archivos de migration plan explícitos a tu repo. Aunque algunas personas prefieren este modelo, nos pareció un paso extra molesto para la mayoría de usuarios tener que recordar ir a crear una migration cada vez que cambiaban su schema.
Conclusión
Estamos contentos con el balance que hemos encontrado en la primera iteración de Astro DB al sentar las bases para futuros use-cases locales mientras proporcionamos una forma fácil de desplegar bases de datos de producción hoy. Un detalle dejado fuera de este artículo es cómo las integraciones pueden proporcionar también sus propias tablas y datos, lo cual esperamos explorar más a medida que continuamos por el camino de construir la próxima iteración de content y plugins en Astro.
Para empezar a integrar tu app, consulta la documentación.
