Logotipo de Bitdoze

Astro DB con Bunny Database: Desarrollo Local-First, libSQL en Producción

Usa Astro DB para desarrollo local-first y aloja la base de datos de producción en el libSQL gestionado de Bunny.net en lugar de Turso.

Dragos

16 min de lectura

Astro DB con Bunny Database: Desarrollo Local-First, libSQL en Producción

Astro DB es una de esas funciones que te hace preguntarte por qué no todos los frameworks incluyen algo así. Defines tablas en TypeScript, obtienes un archivo SQLite local para desarrollo sin configuración alguna, y consultas todo a través de un cliente Drizzle integrado con seguridad de tipos completa. El problema es que la documentación oficial te lleva directamente a Turso para la base de datos de producción, y Turso es la opción obvia por defecto ya que mantienen libSQL.

Pero Astro DB se conecta a cualquier servidor libSQL, no solo a Turso. Y Bunny.net ahora ofrece una base de datos libSQL gestionada que te da la misma URL libsql:// y un token de acceso, está ubicada en la UE, se detiene cuando nadie la consulta y factura por uso. Así que puedes mantener todo el flujo de trabajo local-first de Astro DB y simplemente apuntar la producción a Bunny. Eso es lo que hace esta guía.

Prueba Bunny.net gratis durante 14 días

Necesitarás una cuenta de Bunny para el paso de producción. Regístrate en Bunny.net sin tarjeta de crédito y obtén una prueba de 14 días. Mi reseña completa de Bunny.net cubre el resto de la plataforma.

Cómo encajan Astro DB y Bunny

Aquí está el modelo mental, porque a mí me confundió al principio. Astro DB tiene dos mitades:

  • Desarrollo local: astro dev crea un archivo SQLite en .astro/content.db, regenera tus tipos desde db/config.ts y lo vuelve a sembrar desde db/seed.ts en cada cambio. Sin Docker, sin red, sin credenciales
  • Producción: cuando compilas o ejecutas con el flag --remote, Astro se comunica con un servidor libSQL real definido por dos variables de entorno, ASTRO_DB_REMOTE_URL y ASTRO_DB_APP_TOKEN

La documentación rellena esas dos variables con valores de Turso. Nosotros las vamos a rellenar con valores de Bunny. Todo lo demás de Astro DB, el esquema, el archivo seed, las consultas Drizzle, permanece exactamente igual.

Por qué funciona esto

Bunny Database está construido sobre libSQL, el mismo fork de SQLite que Turso mantiene y el mismo motor que Astro DB usa internamente. Bunny expone el protocolo remoto de libSQL, así que para Astro es simplemente otro endpoint libSQL. La combinación no es una integración oficial de Astro, simplemente surge de que ambos lados hablan libSQL.

Requisitos previos

  • Un proyecto Astro existente, o uno nuevo (npm create astro@latest)
  • Node.js instalado
  • Una cuenta de Bunny.net con acceso a Bunny Database (actualmente en vista previa pública)

Si aún no tienes un sitio Astro, tengo una guía sobre cómo crear un blog gratis con Astro que te da un proyecto funcional al que añadir una base de datos.

Paso 1: Instala la integración de Astro DB

Desde la raíz de tu proyecto, deja que Astro lo configure todo:

bash
npx astro add db

Esto instala @astrojs/db, lo añade a tu astro.config.mjs y crea un db/config.ts inicial:

ts
// db/config.ts
import { defineDb } from 'astro:db';

export default defineDb({
  tables: {},
})

Paso 2: Define tus tablas

Las tablas viven en db/config.ts. Astro lee este archivo para generar una interfaz TypeScript para cada tabla, que es lo que te da autocompletado y errores en tiempo de compilación al consultar.

Aquí hay una tabla Comment con un Author al que referencia, la misma estructura que usan los docs de Astro, para que sea fácil de comparar:

ts
// db/config.ts
import { defineDb, defineTable, column } from 'astro:db';

const Author = defineTable({
  columns: {
    id: column.number({ primaryKey: true }),
    name: column.text(),
  },
});

const Comment = defineTable({
  columns: {
    id: column.number({ primaryKey: true }),
    authorId: column.number({ references: () => Author.columns.id }),
    body: column.text(),
    published: column.date({ default: new Date() }),
  },
});

export default defineDb({
  tables: { Author, Comment },
})

Los tipos de columna se traducen limpiamente a SQLite: column.text(), column.number(), column.boolean(), column.date() (consultada como un Date de JavaScript) y column.json() para un blob sin tipo. La propiedad references en authorId establece la relación de clave foránea con Author.id.

Paso 3: Carga datos de desarrollo local

En desarrollo no tocas los datos de producción. Astro vuelve a sembrar una base de datos local nueva desde db/seed.ts cada vez que el archivo cambia, lo que mantiene tu entorno de desarrollo predecible.

ts
// db/seed.ts
import { db, Author, Comment } from 'astro:db';

export default async function () {
  await db.insert(Author).values([
    { id: 1, name: 'Kasim' },
    { id: 2, name: 'Mina' },
  ]);

  await db.insert(Comment).values([
    { authorId: 1, body: 'Hope you like Astro DB!' },
    { authorId: 2, body: 'Enjoy!' },
  ]);
}

Arranca el servidor de desarrollo y la tabla ya está activa en local:

bash
npm run dev

Paso 4: Consulta la base de datos en una página

Puedes consultar desde cualquier página, endpoint o acción de Astro usando el cliente db exportado desde astro:db. Es Drizzle por dentro, ya configurado, sin necesidad de configurar el cliente.

astro
---
// src/pages/index.astro
import { db, Comment, Author, eq } from 'astro:db';

const comments = await db
  .select()
  .from(Comment)
  .innerJoin(Author, eq(Comment.authorId, Author.id));
---

<h2>Comments</h2>
{
  comments.map(({ Author, Comment }) => (
    <article>
      <p>Author: {Author.name}</p>
      <p>{Comment.body}</p>
    </article>
  ))
}

Todos los helpers de consulta de Drizzle, eq(), gt(), like(), count() y la etiqueta sql cruda, vienen directamente de astro:db:

ts
import { eq, gt, count, sql } from 'astro:db';

En este punto todo se ejecuta contra el archivo local. Ahora vamos a darle un hogar real en Bunny.

Paso 5: Crea tu Bunny Database

  1. Inicia sesión en el panel de Bunny.net
  2. En la barra lateral, haz clic en + Add, luego en Database
  3. Dale un nombre (por ejemplo astro-comments). El nombre aparece en tu URL de conexión
  4. Elige un modo de despliegue. Single region es lo más barato y suficiente para la mayoría de sitios, Automatic deja que Bunny elija las regiones por ti, y Manual te da control sobre el primario y las réplicas
  5. Haz clic en Add Database

Abre la base de datos y ve a la pestaña Access. Necesitas dos cosas aquí:

  • Database URL: tiene el formato libsql://<your-database-id>.lite.bunnydb.net
  • Access Token: haz clic en Generate Tokens y copia el token Full Access (Astro necesita acceso de escritura para enviar el esquema y persistir datos)

Copia el token ahora

Bunny muestra los tokens una sola vez. Si lo pierdes, genera uno nuevo, lo que invalida el anterior. Nunca lo subas a git.

Paso 6: Apunta Astro DB a Bunny

Este es el único paso realmente específico de Bunny, y son solo dos variables de entorno. Mapea los valores de Bunny a las variables que Astro espera:

Variable de Astro Valor de Bunny
ASTRO_DB_REMOTE_URL La URL de tu base de datos Bunny (libsql://...lite.bunnydb.net)
ASTRO_DB_APP_TOKEN Tu token Full Access

Colócalas en un archivo .env en la raíz del proyecto:

bash
# .env
ASTRO_DB_REMOTE_URL="libsql://your-database-id.lite.bunnydb.net"
ASTRO_DB_APP_TOKEN="your-full-access-token"

Asegúrate de que .env está en el gitignore. Ese es todo el cambio. Donde los docs de Astro dicen “establece esto a tu URL de Turso”, tú lo estableces a tu URL de Bunny.

Si el esquema libsql:// te da problemas

Astro DB acepta los esquemas libsql:, https: y wss:. El libSQL de Bunny habla el protocolo remoto sobre HTTPS, así que si una URL libsql:// llega a fallar al conectar desde un runtime concreto, cambia el esquema a https:// en el mismo host (https://your-database-id.lite.bunnydb.net) y mantén el mismo token.

Paso 7: Envía tu esquema a Bunny

Por ahora tu esquema local solo existe en db/config.ts. Envíalo a la base de datos Bunny con el flag --remote:

bash
npx astro db push --remote

Esto crea las tablas Author y Comment en Bunny y verifica que el cambio no perderá datos existentes. Si más adelante haces un cambio de esquema incompatible y no te importa borrar la producción, añade --force-reset:

bash
npx astro db push --remote --force-reset

Para cargar datos reales en la base de datos remota (no solo los datos seed locales), ejecuta un archivo seed o de migración contra ella con execute:

bash
npx astro db execute db/seed.ts --remote

Paso 8: Compila y despliega contra Bunny

En local, dev y build usan el archivo local por defecto. Para que producción lea y escriba en Bunny, añade --remote a tu comando de build en package.json:

json
{
  "scripts": {
    "build": "astro build --remote"
  }
}

También puedes pasarlo directamente cuando quieras una sesión de desarrollo conectada al remoto:

bash
# Build against the Bunny database
astro build --remote

# Develop against the Bunny database
astro dev --remote

Define ASTRO_DB_REMOTE_URL y ASTRO_DB_APP_TOKEN también en el entorno de tu plataforma de despliegue, no solo en local. El flag --remote usa la conexión durante el build y en el servidor, así que ambos entornos necesitan las credenciales.

Las escrituras necesitan renderizado bajo demanda

Leer datos en tiempo de compilación funciona con un sitio estático. Pero para escribir (aceptar un formulario de comentarios, por ejemplo) necesitas renderizado bajo demanda con un adaptador para tu hosting (Node, un VPS, Cloudflare, etc.). Un build puramente estático puede leer de Bunny en tiempo de compilación pero no puede persistir filas nuevas en tiempo de ejecución.

Aceptar datos de usuarios: un formulario de comentarios

Aquí está la ruta de escritura, usando una acción de Astro para obtener validación con Zod gratis. Esto asume que has añadido un adaptador y habilitado el renderizado bajo demanda.

ts
// src/actions/index.ts
import { db, Comment } from 'astro:db';
import { defineAction } from 'astro:actions';
import { z } from 'astro/zod';

export const server = {
  addComment: defineAction({
    input: z.object({
      authorId: z.number(),
      body: z.string(),
    }),
    handler: async (input) => {
      const created = await db.insert(Comment).values(input).returning();
      return created;
    },
  }),
};

Como la acción se ejecuta en el servidor, tu token de Bunny nunca llega al navegador. El insert va directamente a la base de datos libSQL remota y returning() devuelve la fila nueva.

Réplicas embebidas para lecturas más rápidas

Una función de libSQL que vale la pena conocer: las réplicas embebidas. Puedes mantener una copia local sincronizada de la base de datos Bunny para lecturas muy rápidas, con las escrituras reenviadas a Bunny. Astro lo configura mediante parámetros de consulta en la URL remota:

bash
# In-memory replica synced from Bunny, refreshing every 60s
ASTRO_DB_REMOTE_URL="memory:?syncUrl=libsql%3A%2F%2Fyour-database-id.lite.bunnydb.net&syncInterval=60"
ASTRO_DB_APP_TOKEN="your-full-access-token"

El valor de syncUrl debe estar codificado para URL. Esto es exagerado para un blog pequeño, pero si ejecutas un sitio con muchas lecturas en un solo servidor, convierte la mayoría de lecturas en consultas locales mientras Bunny sigue siendo la fuente de verdad.

Por qué combinar Astro DB con Bunny en lugar de Turso

Ambos son sólidos. Así es como yo planteo la elección:

Bunny Database Turso
Motor libSQL libSQL
Funciona con Astro DB Sí (define las dos variables de entorno) Sí (ejemplo oficial)
Facturación en reposo Se detiene cuando está inactivo Nivel gratuito, luego por uso
Mismo panel que CDN/almacenamiento Sí No
Región Empresa de la UE (Eslovenia) Con sede en EE. UU.
Estado Vista previa pública GA

Si ya ejecutas tu CDN, almacenamiento o vídeo en Bunny, mantener la base de datos en el mismo panel y en la misma factura es la ventaja obvia. Si quieres el host libSQL más maduro, en GA y con las herramientas más profundas, Turso sigue siendo la opción segura. Como ambos son libSQL, puedes cambiar entre ellos más adelante modificando dos variables de entorno y reenviando el esquema, así que no es una puerta de un solo sentido.

Solución de problemas

astro db push --remote falla al conectar

Comprueba que ASTRO_DB_REMOTE_URL apunta al host exacto de tu base de datos Bunny y que ASTRO_DB_APP_TOKEN es el token Full Access, no Read Only. Si una URL libsql:// no conecta desde tu runtime, prueba el esquema https:// en el mismo host.

Las lecturas funcionan pero las escrituras fallan en producción

Un build estático puede leer en tiempo de compilación pero no puede escribir en tiempo de ejecución. Añade un adaptador y habilita el renderizado bajo demanda para que tus formularios y acciones puedan persistir datos en Bunny.

Los cambios locales no aparecen en producción

dev y build locales usan el archivo local a menos que pases --remote. Envía los cambios de esquema con astro db push --remote, y asegúrate de que tu comando de build de despliegue incluye el flag --remote.

Errores de permisos o de solo lectura

Probablemente estás usando un token de solo lectura. Genera un token Full Access en la pestaña Access de la base de datos Bunny y actualiza ASTRO_DB_APP_TOKEN en todas partes.

Preguntas frecuentes

¿Es una integración oficial de Astro?

No. No hay un plugin de Astro específico para Bunny. Funciona porque Astro DB se conecta a cualquier servidor libSQL mediante ASTRO_DB_REMOTE_URL y ASTRO_DB_APP_TOKEN, y Bunny Database es libSQL. Estás usando el mismo mecanismo de base de datos remota que los docs demuestran con Turso.

¿Puedo seguir desarrollando en local sin tocar Bunny?

Sí, y ese es todo el atractivo. El npm run dev del día a día usa el archivo SQLite local y tus datos seed. Solo tocas Bunny cuando envías el esquema o compilas con --remote. Mantiene los datos de producción seguros mientras trabajas.

¿Bunny cobra por consulta?

Bunny Database factura por uso (lecturas, escrituras y almacenamiento por región activa) y se detiene cuando nada lo consulta, así que un sitio Astro con poco tráfico cuesta muy poco. Consulta la página de precios de Bunny para las tarifas actuales de la vista previa.

¿Y si prefiero usar Drizzle directamente sin Astro DB?

Puedes. Astro DB envuelve Drizzle con un flujo de configuración y seed más agradable, pero si quieres Drizzle en crudo contra una base de datos libSQL, escribí una guía de TanStack Start + Bunny Database + Drizzle que usa @libsql/client y Drizzle directamente. Misma base de datos, framework diferente y una configuración ORM más manual.

¿Puedo migrar a Turso más adelante, o viceversa?

Sí. Ambos son libSQL, así que cambiar de host significa cambiar ASTRO_DB_REMOTE_URL y ASTRO_DB_APP_TOKEN y ejecutar astro db push --remote contra la nueva base de datos. También puedes volcar e importar datos con las CLI respectivas.

Conclusión

Astro DB te da un flujo de trabajo local-first realmente agradable: tablas tipadas, SQLite local instantáneo y un cliente Drizzle que no necesita cableado. Los docs te dirigen a Turso para producción, pero la conexión remota es simplemente libSQL, así que apuntarla a Bunny es un cambio de dos variables. Obtienes una base de datos que vive en el mismo panel que tu CDN y almacenamiento, se detiene cuando el tráfico está quieto y sigue siendo portable porque es libSQL puro por debajo.

Si tu sitio ya funciona estático en Bunny, esto cierra el círculo: páginas estáticas desde el CDN, datos dinámicos desde Bunny Database, todo en una factura.

Prueba Bunny.net Gratis durante 14 Días

Artículos relacionados