Configurar el adapter y las APIs del runtime
Más allá de instalar el adapter: cómo se combinan output y adapter en astro.config, cómo platformProxy hace que astro dev emule los bindings de Cloudflare en tu máquina, por qué la optimización de imágenes cambia en el edge cuando Sharp no puede correr, y cómo alcanzar las APIs específicas del runtime —KV, D1, geolocalización, trabajo diferido y sesiones— a través de Astro.locals.runtime.
adapter en astro.config, con sus opciones
La clave adapter recibe la función del adapter, y esa función acepta un objeto de opciones que ajusta su comportamiento. El output decide la política de renderizado —static con rutas dinámicas puntuales, o server con todo bajo demanda por defecto—; el adapter decide el destino. Juntos definen cómo y dónde corre tu sitio.
import { defineConfig } from 'astro/config';import cloudflare from '@astrojs/cloudflare';export default defineConfig({ output: 'server', adapter: cloudflare({ platformProxy: { enabled: true }, imageService: 'cloudflare', }),});astro add deja esta clave con valores por defecto sensatos; tu trabajo posterior es afinar las opciones según lo que la plataforma ofrezca. Cada adapter documenta las suyas, pero dos familias de opciones aparecen una y otra vez: las que emulan el runtime en desarrollo y las que redirigen servicios —imágenes, sesiones— hacia lo que el destino sí soporta.
platformProxy: el runtime de la plataforma en tu máquina
Cloudflare expone recursos —KV, R2, D1, secretos, la información geográfica de la petición— a través de bindings que solo existen dentro de su runtime. Esos bindings se declaran en el fichero de Wrangler, y de ahí los toma tanto la plataforma real como la emulación local.
// wrangler.jsonc{ "kv_namespaces": [{ "binding": "MI_KV", "id": "..." }], "d1_databases": [{ "binding": "DB", "database_name": "prod" }]}En astro dev, sin más, esos bindings no están, y Astro.locals.runtime llega vacío. La opción platformProxy: { enabled: true } resuelve el desfase: usa Wrangler por debajo para levantar emulaciones locales de esos recursos y poblar Astro.locals.runtime como lo haría la plataforma real.
---// una pagina bajo demanda en Cloudflareconst { env, cf, ctx } = Astro.locals.runtime;const guardado = await env.MI_KV.get('clave'); // binding KVctx.waitUntil(registrarVisita(cf.country)); // trabajo diferido---<p>Servido desde {cf.city}</p>Con platformProxy activo, ese código funciona igual en tu portátil que en producción: lees de un KV emulado, consultas el país de la petición, programas trabajo diferido con ctx.waitUntil. Sin él, tendrías que desplegar para probar cualquier cosa que toque un binding —un ciclo de desarrollo lento y a ciegas—.
Para que Astro.locals.runtime deje de ser any, su tipo se declara una vez en src/env.d.ts. El adapter de Cloudflare exporta un tipo Runtime parametrizado con tu Env —el que genera Wrangler a partir de tus bindings—, y lo enlazas a App.Locals:
// src/env.d.tstype Runtime = import('@astrojs/cloudflare').Runtime<Env>;declare namespace App { interface Locals extends Runtime {}}Imágenes y servicios que dependen del runtime
El servicio de imágenes de Astro usa por defecto Sharp, un módulo nativo de Node. En el edge no hay módulos nativos, así que optimizar imágenes bajo demanda ahí exige otro camino. El adapter de Cloudflare expone imageService para elegirlo, y ese menú resume el patrón general: cuando el runtime no soporta la implementación por defecto, el adapter ofrece una específica de la plataforma.
adapter: cloudflare({ imageService: 'cloudflare', // redimensionado en el edge, sin Sharp}),La lección general trasciende las imágenes: cualquier capacidad que en Node dabas por sentada —procesar un PDF, comprimir con una librería nativa, leer una fuente del disco— hay que replantearla en el edge como un servicio de la plataforma o una llamada a una API externa. El adapter te dice qué tienes disponible; el runtime, qué te falta y por dónde suplirlo.
Trabajo diferido y sesiones en el runtime
El runtime no solo se lee: también difiere trabajo y guarda estado. ctx.waitUntil acepta una promesa que la plataforma mantiene viva después de enviar la respuesta —registrar una analítica, calentar un caché, escribir un log— sin retrasar al usuario ni un milisegundo. Y el almacenamiento del runtime puede respaldar a Astro: en Cloudflare, un binding KV sirve de trastienda al sistema de sesiones, de modo que Astro.session persiste entre peticiones usando la infraestructura de la propia plataforma.
---const { ctx, env } = Astro.locals.runtime;// responde ya y registra la visita despues, sin bloquearctx.waitUntil(env.LOGS.put(crypto.randomUUID(), JSON.stringify({ t: Date.now() })));---Estas APIs del runtime —los bindings, la geolocalización, el trabajo diferido, el almacenamiento— son puertas de poder, pero también son puntos de acoplamiento. Astro.locals.runtime.env no existe en Node ni en Vercel; cf.country es vocabulario de Cloudflare. Usarlas es legítimo y a menudo la razón misma de elegir esa plataforma, pero conviene saber que cada una es un hilo que te ata al destino.