From harness-claude
Configures Astro adapters, environment variables, and build output for deploying to Vercel, Node.js, Cloudflare, and Netlify. Useful for first-time deploys, target switches, env management, and production debugging.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Configure adapters, environment variables, and build output for deploying Astro to Vercel, Node.js, Cloudflare, and Netlify.
Provides Astro framework patterns for islands architecture, content collections, rendering strategies (SSG, SSR, hybrid), view transitions, partial hydration, and Cloudflare deployment.
Guides deploying frameworks (Vite/React, Astro, TanStack Start, Next.js, Nuxt, SvelteKit, Remix) to Netlify using adapters for SSR, Edge Functions, redirects, 404s, and env vars.
Configures Astro SSR and hybrid rendering to mix static pre-rendered pages with dynamic server-rendered ones. Covers output modes, prerender flags, adapters for Vercel/Node/Cloudflare, requests, cookies, redirects.
Share bugs, ideas, or general feedback.
Configure adapters, environment variables, and build output for deploying Astro to Vercel, Node.js, Cloudflare, and Netlify.
# Vercel (serverless functions)
npx astro add vercel
# Vercel Edge (edge runtime — limited Node.js APIs)
# Manual: import vercel from '@astrojs/vercel/edge'
# Node.js (self-hosted server)
npx astro add node
# Cloudflare Pages
npx astro add cloudflare
# Netlify
npx astro add netlify
astro.config.mjs:// Vercel — serverless (most common)
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
output: 'server',
adapter: vercel({
webAnalytics: { enabled: true },
imageService: true, // use Vercel Image Optimization
devImageService: 'sharp', // local dev uses sharp
}),
});
// Node.js — standalone server
import node from '@astrojs/node';
export default defineConfig({
output: 'server',
adapter: node({ mode: 'standalone' }), // or 'middleware' for Express
});
// Cloudflare Pages
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
output: 'server',
adapter: cloudflare({ mode: 'directory' }), // or 'advanced'
});
import.meta.env. Astro follows Vite's env convention:// Public variables (exposed to client bundles) — must be prefixed PUBLIC_
const apiBase = import.meta.env.PUBLIC_API_BASE_URL;
// Server-only variables (never sent to client)
const dbUrl = import.meta.env.DATABASE_URL;
const secretKey = import.meta.env.SECRET_KEY;
// Built-in variables
const isDev = import.meta.env.DEV; // boolean
const isProd = import.meta.env.PROD; // boolean
const siteUrl = import.meta.env.SITE; // set in astro.config.mjs > site
const baseUrl = import.meta.env.BASE_URL; // set in astro.config.mjs > base
.env files (never commit secrets):# .env (committed — only PUBLIC_ vars)
PUBLIC_API_BASE_URL=https://api.example.com
# .env.local (gitignored — secrets)
DATABASE_URL=postgres://...
SECRET_KEY=abc123
# .env.production (committed — production public vars only)
PUBLIC_API_BASE_URL=https://api.production.com
// astro.config.mjs
export default defineConfig({
output: 'static', // default — no adapter needed
site: 'https://example.com',
base: '/docs', // if deployed to a subdirectory
build: {
assets: '_assets', // custom directory for built assets (default: '_astro')
},
});
Deploy the dist/ directory to any static host (GitHub Pages, Netlify, Cloudflare Pages in static mode, S3 + CloudFront).
astro.config.mjs for static deployments:export default defineConfig({
redirects: {
'/old-blog': '/blog',
'/old-blog/[slug]': '/blog/[slug]',
},
});
For SSR deployments, platform-specific config files take precedence:
vercel.json (headers, rewrites)netlify.toml (headers, redirects, functions)wrangler.toml + _headers / _redirects filessite in astro.config.mjs — it is required for canonical URLs, sitemaps, and the SITE env variable:export default defineConfig({
site: 'https://www.example.com', // must be the full URL including protocol
});
# Build
npx astro build
# Start (standalone mode)
node ./dist/server/entry.mjs
# With environment variables
DATABASE_URL=postgres://... node ./dist/server/entry.mjs
# Configure the host/port
HOST=0.0.0.0 PORT=3000 node ./dist/server/entry.mjs
Adapter selection guide:
| Platform | Adapter | Notes |
|---|---|---|
| Vercel | @astrojs/vercel/serverless | Best DX; automatic image optimization |
| Vercel Edge | @astrojs/vercel/edge | No Node.js built-ins; lower latency |
| Netlify | @astrojs/netlify | Functions + Edge Functions |
| Cloudflare Pages | @astrojs/cloudflare | Workers runtime; no Node.js fs module |
| AWS Lambda | @astrojs/node + custom wrapper | Requires additional glue |
| Docker / VPS | @astrojs/node standalone | Full control; bring your own process manager |
| GitHub Pages | none (static) | Free; limited to output: 'static' |
Cloudflare-specific considerations:
Cloudflare Workers do not support Node.js built-in modules (fs, path, crypto from Node.js). Use the Cloudflare-native equivalents: crypto.subtle for crypto, KV / R2 for storage. Add { mode: 'directory' } to the Cloudflare adapter when deploying to Pages (as opposed to Workers).
Environment variables at runtime vs. build time:
SECRET_* vars in SSG are only available in the build process and getStaticPaths(). They are never included in client bundles.base path configuration:
When deploying to a subdirectory (e.g., GitHub Pages project site at /repo-name/), set base: '/repo-name'. Astro prefixes all internal links, assets, and the router with this base. Access it via import.meta.env.BASE_URL.
Build output structure:
dist/ — build output rootdist/index.html — static pages (SSG)dist/_astro/ — hashed JS/CSS chunksdist/server/ — SSR entry point and chunks (when using an adapter)CI/CD patterns:
Most platforms (Vercel, Netlify, Cloudflare Pages) auto-detect Astro projects and set the build command (astro build) and output directory (dist/) automatically. For Node.js self-hosted deployments, set up a process manager (PM2, systemd) to keep the server running and restart on crash.
https://docs.astro.build/en/guides/deploy