Skip to content

Deploy

Kide CMS builds on Astro, so you can deploy it anywhere Astro runs. The setup script provides installation helpers for two targets: Node.js (local SQLite) and Cloudflare Workers (D1 + R2), configuring the database, storage, and image optimization for your choice.

Terminal window
pnpx create-kide-app my-site
# Select "Cloudflare" when prompted

This generates a wrangler.toml with D1 and R2 bindings.

Terminal window
cd my-site
pnpm dlx wrangler d1 create my-site-db
pnpm dlx wrangler r2 bucket create my-site-assets

Copy the database_id from the D1 create output into wrangler.toml.

Terminal window
pnpm dlx wrangler d1 execute my-site-db --remote --file=src/cms/migrations/0000_init.sql
Terminal window
pnpm run deploy

This builds the Astro app and deploys it as a Cloudflare Worker.

The generated wrangler.toml:

name = "my-site"
compatibility_date = "2025-01-01"
compatibility_flags = ["nodejs_compat"]
[[d1_databases]]
binding = "CMS_DB"
database_name = "my-site-db"
database_id = "" # from wrangler d1 create
[triggers]
crons = ["* * * * *"] # scheduled publishing
[[r2_buckets]]
binding = "CMS_ASSETS"
bucket_name = "my-site-assets"

On Cloudflare, assets are stored in R2 instead of the local filesystem. The CMS uses a storage abstraction (src/cms/core/storage.ts) that the setup script configures:

  • Local/Node.js: Files go to public/uploads/, served by Astro’s static file handling
  • Cloudflare: Files go to R2 via the CMS_ASSETS binding, served by a dynamic route at /uploads/[...path].ts

No code changes needed. The setup script copies the correct storage.ts for your target.

  • Local/Node.js: SQLite via better-sqlite3, stored at data/cms.db
  • Cloudflare: D1 (Cloudflare’s distributed SQLite), accessed via the CMS_DB binding

The setup script copies the correct db.ts for your target, similar to storage.

Kide CMS supports scheduled publish/unpublish for content. The approach differs by target:

A cron trigger fires every minute. The CMS integration injects a scheduled handler into the built worker entry that calls /api/cms/cron/publish internally.

Set the CRON_SECRET env var on your worker to secure the endpoint:

Terminal window
pnpm dlx wrangler secret put CRON_SECRET

Set up an external cron job to call the publish endpoint:

Terminal window
# crontab
* * * * * curl -s -H "Authorization: Bearer YOUR_SECRET" http://localhost:4321/api/cms/cron/publish

Set CRON_SECRET in your .env to match.

In dev mode, the middleware handles scheduled publishing on every request (no external cron needed).

  • Local/Node.js: Sharp-based on-demand transformation via /api/cms/img/
  • Cloudflare: Cloudflare Image Resizing via /cdn-cgi/image/. Sharp is not used.

The cmsImage() and cmsSrcset() helpers detect the runtime and generate the correct URLs automatically.

Set these on your Cloudflare Worker (dashboard or wrangler secret put):

VariableRequiredDescription
CRON_SECRETRecommendedSecures the scheduled publishing endpoint
RESEND_API_KEYOptionalEnables automatic invite emails via Resend
RESEND_FROM_EMAILOptionalEmail sender address
CF_BEACON_TOKENOptionalCloudflare Web Analytics token
AI_PROVIDEROptionalAI provider for content generation
AI_API_KEYOptionalAI provider API key
AI_MODELOptionalAI model name

For Cloudflare projects, pnpm dev uses Astro’s dev server with local D1/R2 emulation via miniflare. Your wrangler.toml bindings work locally without any extra setup.

For Node.js targets, the build output is a standalone server:

Terminal window
pnpm build
node dist/server/entry.mjs

No extra configuration needed. SQLite database and uploads are stored locally.