Deploying Astro Documentation
This guide covers deploying the VibeCode documentation site built with Astro and Starlight to various hosting platforms.
Overview
Section titled “Overview”The VibeCode documentation is a static site built with:
- Framework: Astro 5.14.4 with Starlight 0.35.1
- Build Time: ~4.12 seconds
- Total Pages: 96 pages
- Output Size: ~13 MB (static HTML/CSS/JS)
- Search: Pagefind (95 pages indexed)
- Hosting: Any static hosting platform
Prerequisites
Section titled “Prerequisites”- Node.js 18.18.0 or higher
- npm 9.0.0 or higher
- Git (for version control)
Building for Production
Section titled “Building for Production”Local Build
Section titled “Local Build”# Navigate to docs directorycd docs
# Install dependenciesnpm install
# Build for productionnpm run build
# Output directory: dist/# Build includes:# - Static HTML pages# - Optimized CSS and JavaScript# - Pagefind search index# - Optimized imagesBuild Configuration
Section titled “Build Configuration”The build is configured in astro.config.mjs:
export default defineConfig({ site: 'https://ryanmaclean.github.io', base: '/vibecode-webgui', trailingSlash: 'always', integrations: [ starlight({ title: 'VibeCode Platform', // ... configuration }), ],});Key Configuration Options:
site: Your full domain URLbase: Base path for GitHub Pages deploymenttrailingSlash: Ensures consistent URLs
Preview Build Locally
Section titled “Preview Build Locally”# Start preview servernpm run preview
# Test all functionality before deployingDeployment Platforms
Section titled “Deployment Platforms”GitHub Pages (Current Setup)
Section titled “GitHub Pages (Current Setup)”The documentation is currently configured for GitHub Pages deployment.
Automatic Deployment
Section titled “Automatic Deployment”Already configured! Push to main branch and GitHub Actions will deploy automatically.
# Make changesgit add .git commit -m "Update documentation"git push origin main
# GitHub Actions builds and deploys to gh-pages branch# Live at: https://ryanmaclean.github.io/vibecode-webgui/Configuration
Section titled “Configuration”astro.config.mjs:
export default defineConfig({ site: 'https://ryanmaclean.github.io', base: '/vibecode-webgui', // Repository name trailingSlash: 'always',});GitHub Settings:
- Go to repository Settings > Pages
- Source: Deploy from a branch
- Branch:
gh-pages/root - Save
Custom Domain (Optional)
Section titled “Custom Domain (Optional)”-
Add
CNAMEfile topublic/directory:docs.vibecode.com -
Update
astro.config.mjs:export default defineConfig({site: 'https://docs.vibecode.com',base: '/', // Remove base path for custom domain}); -
Configure DNS:
Type: CNAMEName: docsValue: ryanmaclean.github.io
Vercel
Section titled “Vercel”Deploy with zero configuration.
Quick Deploy
Section titled “Quick Deploy”# Install Vercel CLInpm install -g vercel
# From docs directorycd docsvercel --prod
# Or connect GitHub repository for automatic deploymentsConfiguration File
Section titled “Configuration File”Create vercel.json in docs directory:
{ "buildCommand": "npm run build", "outputDirectory": "dist", "framework": "astro", "installCommand": "npm install", "devCommand": "npm run dev"}Environment Variables
Section titled “Environment Variables”In Vercel Dashboard > Settings > Environment Variables:
# Optional: Datadog RUM monitoringPUBLIC_DATADOG_CLIENT_TOKEN=your_client_tokenPUBLIC_DATADOG_APPLICATION_ID=your_app_idBenefits
Section titled “Benefits”- CDN: Global edge network
- SSL: Automatic HTTPS
- Previews: Preview deployments for PRs
- Analytics: Built-in web analytics
- Zero config: Works out of the box
Netlify
Section titled “Netlify”Simple deployment with powerful features.
Quick Deploy
Section titled “Quick Deploy”# Install Netlify CLInpm install -g netlify-cli
# From docs directorycd docsnetlify deploy --prod
# Or drag-and-drop dist/ folder in Netlify UIConfiguration File
Section titled “Configuration File”Create netlify.toml in docs directory:
[build] command = "npm run build" publish = "dist" base = "docs"
[build.environment] NODE_VERSION = "18"
# Optimize images[[plugins]] package = "@netlify/plugin-lighthouse"
# Cache dependencies[[plugins]] package = "netlify-plugin-cache" [plugins.inputs] paths = ["node_modules", ".astro"]
# Redirects and rewrites[[redirects]] from = "/*" to = "/404.html" status = 404
# Headers for security and performance[[headers]] for = "/*" [headers.values] X-Frame-Options = "DENY" X-XSS-Protection = "1; mode=block" X-Content-Type-Options = "nosniff" Referrer-Policy = "strict-origin-when-cross-origin"
[[headers]] for = "/_astro/*" [headers.values] Cache-Control = "public, max-age=31536000, immutable"
[[headers]] for = "/*.css" [headers.values] Cache-Control = "public, max-age=31536000, immutable"
[[headers]] for = "/*.js" [headers.values] Cache-Control = "public, max-age=31536000, immutable"Environment Variables
Section titled “Environment Variables”In Netlify Dashboard > Site settings > Environment variables:
PUBLIC_DATADOG_CLIENT_TOKEN=your_tokenPUBLIC_DATADOG_APPLICATION_ID=your_app_idBenefits
Section titled “Benefits”- Forms: Built-in form handling
- Functions: Serverless functions support
- Deploy previews: PR previews
- Split testing: A/B testing
- Analytics: Built-in analytics
Cloudflare Pages
Section titled “Cloudflare Pages”Fast global deployment with Cloudflare’s edge network.
Quick Deploy
Section titled “Quick Deploy”-
Via Dashboard:
- Go to Cloudflare Pages
- Connect GitHub repository
- Configure build settings:
- Build command:
npm run build - Build output directory:
dist - Root directory:
docs
- Build command:
-
Via Wrangler CLI:
Terminal window # Install Wranglernpm install -g wrangler# Deploycd docsnpx wrangler pages deploy dist
Configuration
Section titled “Configuration”Create wrangler.toml:
name = "vibecode-docs"compatibility_date = "2025-10-25"
[site] bucket = "dist"
[[routes]] pattern = "docs.vibecode.com/*" zone_name = "vibecode.com"Custom Headers
Section titled “Custom Headers”In Cloudflare Pages > Settings > Custom domains > HTTP Headers:
/* X-Frame-Options: DENY X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: geolocation=(), microphone=(), camera=()
/_astro/* Cache-Control: public, max-age=31536000, immutableBenefits
Section titled “Benefits”- Speed: Cloudflare’s global CDN
- DDoS protection: Built-in security
- Analytics: Cloudflare Web Analytics
- Workers: Edge compute capabilities
- Free tier: Unlimited bandwidth
AWS S3 + CloudFront
Section titled “AWS S3 + CloudFront”Enterprise-grade static hosting.
Deployment Steps
Section titled “Deployment Steps”-
Create S3 Bucket:
Terminal window aws s3 mb s3://vibecode-docsaws s3 website s3://vibecode-docs --index-document index.html --error-document 404.html -
Configure Bucket Policy:
{"Version": "2012-10-17","Statement": [{"Sid": "PublicReadGetObject","Effect": "Allow","Principal": "*","Action": "s3:GetObject","Resource": "arn:aws:s3:::vibecode-docs/*"}]} -
Deploy Files:
Terminal window cd docsnpm run buildaws s3 sync dist/ s3://vibecode-docs/ --delete -
Create CloudFront Distribution:
Terminal window aws cloudfront create-distribution \--origin-domain-name vibecode-docs.s3.amazonaws.com \--default-root-object index.html -
Invalidate Cache After Deploy:
Terminal window aws cloudfront create-invalidation \--distribution-id DISTRIBUTION_ID \--paths "/*"
Automated Deployment Script
Section titled “Automated Deployment Script”#!/bin/bashset -euo pipefail
BUCKET="vibecode-docs"DISTRIBUTION_ID="your-distribution-id"
echo "Building documentation..."npm run build
echo "Syncing to S3..."aws s3 sync dist/ s3://${BUCKET}/ \ --delete \ --cache-control "public, max-age=31536000" \ --exclude "*.html" \ --exclude "_pagefind/*"
aws s3 sync dist/ s3://${BUCKET}/ \ --delete \ --cache-control "public, max-age=3600" \ --exclude "*" \ --include "*.html" \ --include "_pagefind/*"
echo "Invalidating CloudFront cache..."aws cloudfront create-invalidation \ --distribution-id ${DISTRIBUTION_ID} \ --paths "/*"
echo "Deployment complete!"Azure Static Web Apps
Section titled “Azure Static Web Apps”Deploy to Microsoft Azure.
Quick Deploy
Section titled “Quick Deploy”# Install Azure CLIbrew install azure-cli # macOS# or download from https://aka.ms/installazurecliwindows
# Loginaz login
# Create static web appaz staticwebapp create \ --name vibecode-docs \ --resource-group vibecode-rg \ --location eastus2
# Deploycd docsnpm run buildaz staticwebapp deploy \ --app-name vibecode-docs \ --output-path distGitHub Actions Workflow
Section titled “GitHub Actions Workflow”Azure provides automatic deployment via GitHub Actions:
name: Azure Static Web Apps CI/CD
on: push: branches: - main paths: - 'docs/**'
jobs: build_and_deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Build working-directory: ./docs run: | npm ci npm run build
- name: Deploy uses: Azure/static-web-apps-deploy@v1 with: azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }} action: "upload" app_location: "docs/dist"CDN Configuration
Section titled “CDN Configuration”Caching Strategy
Section titled “Caching Strategy”Configure appropriate cache headers for optimal performance:
Long-term caching (1 year):
/_astro/*- Hashed asset files/*.css- Stylesheet files/*.js- JavaScript files/fonts/*- Font files
Short-term caching (1 hour):
/*.html- HTML pages/_pagefind/*- Search index
No caching:
/404.html- Error page/api/*- API endpoints (if any)
Example Headers
Section titled “Example Headers”# Long-term caching/_astro/* Cache-Control: public, max-age=31536000, immutable
# Short-term caching/*.html Cache-Control: public, max-age=3600
/_pagefind/* Cache-Control: public, max-age=3600
# No caching/404.html Cache-Control: no-cache, no-store, must-revalidateSearch Configuration
Section titled “Search Configuration”The documentation uses Pagefind for static search.
Pagefind Setup
Section titled “Pagefind Setup”Pagefind is automatically built during astro build:
# Build includes Pagefind indexingnpm run build
# Output includes:# dist/_pagefind/# ├── pagefind.js# ├── pagefind-ui.js# ├── pagefind-ui.css# └── pagefind-entry.jsonEnsuring Search Works
Section titled “Ensuring Search Works”After deployment, verify:
-
Search index exists:
Terminal window curl https://your-domain.com/_pagefind/pagefind-entry.json# Should return JSON data -
Search UI loads:
- Visit any page
- Open search (Cmd/Ctrl + K)
- Try searching for “deployment”
-
Search results work:
- Results should appear as you type
- Clicking results should navigate to pages
Troubleshooting Search
Section titled “Troubleshooting Search”Issue: Search not working after deployment
# Check if _pagefind directory was deployedls -la dist/_pagefind/
# Ensure build ran successfullynpm run build 2>&1 | grep -i pagefind
# Look for: "Generated Pagefind search index"Issue: Search index is empty
# Pagefind might be skipping pages# Check page frontmatter doesn't have:# pagefind: false
# Rebuild with verbose outputDEBUG=pagefind:* npm run buildPerformance Optimization
Section titled “Performance Optimization”Build Optimization
Section titled “Build Optimization”export default defineConfig({ build: { inlineStylesheets: 'auto', }, compressHTML: true, integrations: [ starlight({ // Optimize for production customCss: ['./src/styles/custom.css'], }), ],});Image Optimization
Section titled “Image Optimization”Astro automatically optimizes images in the src/ directory:
<!-- Uses Astro's image optimization -->
<!-- For external images -->Font Optimization
Section titled “Font Optimization”Use font subsetting to reduce font file size:
@font-face { font-family: 'Inter'; font-display: swap; /* Prevent font rendering blocking */ src: url('/fonts/inter-subset.woff2') format('woff2'); unicode-range: U+0000-00FF; /* Latin characters only */}Monitoring & Analytics
Section titled “Monitoring & Analytics”Datadog RUM
Section titled “Datadog RUM”Already configured in astro.config.mjs:
head: [ { tag: 'script', attrs: { src: 'https://www.datadoghq-browser-agent.com/us5/v5/datadog-rum.js', }, }, { tag: 'script', content: ` if (typeof window !== 'undefined' && import.meta.env.PUBLIC_DATADOG_CLIENT_TOKEN) { window.DD_RUM.init({ clientToken: import.meta.env.PUBLIC_DATADOG_CLIENT_TOKEN, applicationId: import.meta.env.PUBLIC_DATADOG_APPLICATION_ID, site: 'datadoghq.com', service: 'vibecode-docs', env: 'production', version: '1.0.0', sessionSampleRate: 100, sessionReplaySampleRate: 20, trackUserInteractions: true, trackResources: true, trackLongTasks: true, }); } `, },],Set environment variables:
PUBLIC_DATADOG_CLIENT_TOKEN=your_tokenPUBLIC_DATADOG_APPLICATION_ID=your_app_idGoogle Analytics
Section titled “Google Analytics”Add to astro.config.mjs:
head: [ { tag: 'script', attrs: { async: true, src: 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX', }, }, { tag: 'script', content: ` window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-XXXXXXXXXX'); `, },],Plausible Analytics (Privacy-Friendly)
Section titled “Plausible Analytics (Privacy-Friendly)”head: [ { tag: 'script', attrs: { defer: true, 'data-domain': 'docs.vibecode.com', src: 'https://plausible.io/js/script.js', }, },],Testing Deployment
Section titled “Testing Deployment”Pre-Deployment Checklist
Section titled “Pre-Deployment Checklist”- Build completes without errors
- All pages render correctly locally (
npm run preview) - Search functionality works
- All images load
- All links work (no 404s)
- Mobile responsive layout
- Fast page load times
Automated Testing
Section titled “Automated Testing”# Build and testnpm run buildnpm run preview &PREVIEW_PID=$!
# Wait for serversleep 5
# Test homepagecurl -f http://localhost:4321/vibecode-webgui/ || echo "Homepage failed"
# Test search indexcurl -f http://localhost:4321/vibecode-webgui/_pagefind/pagefind-entry.json || echo "Search failed"
# Kill preview serverkill $PREVIEW_PIDLighthouse CI
Section titled “Lighthouse CI”# Install Lighthouse CInpm install -g @lhci/cli
# Run auditlhci autorun --collect.url=https://your-docs-site.com
# Target scores:# Performance: 95+# Accessibility: 95+# Best Practices: 95+# SEO: 95+Troubleshooting
Section titled “Troubleshooting”Build Errors
Section titled “Build Errors”Issue: Out of memory during build
# Increase Node.js memoryNODE_OPTIONS="--max-old-space-size=4096" npm run buildIssue: Module not found errors
# Clear cache and reinstallrm -rf node_modules package-lock.json .astronpm installnpm run buildDeployment Issues
Section titled “Deployment Issues”Issue: 404 on all pages except homepage
- Check
basepath inastro.config.mjs - Ensure trailing slashes are consistent
- Verify hosting platform configuration
Issue: Assets not loading (CSS/JS)
- Check browser console for CORS errors
- Verify
siteURL inastro.config.mjs - Ensure
basepath matches deployment
Issue: Search not working
# Verify search index was builtls -la dist/_pagefind/
# Check browser console for errors# Common issue: wrong base path
# Rebuild with clean cacherm -rf .astro distnpm run buildPerformance Issues
Section titled “Performance Issues”Issue: Slow page loads
- Enable CDN caching headers
- Compress images (use WebP/AVIF)
- Minimize custom CSS
- Enable compression (Gzip/Brotli)
- Use font subsetting
Issue: Large bundle size
# Analyze build outputnpm run build -- --stats
# Check for:# - Large images (optimize with Astro Image)# - Unused dependencies (remove from package.json)# - Large CSS files (minimize custom styles)Security Best Practices
Section titled “Security Best Practices”Content Security Policy
Section titled “Content Security Policy”Add CSP headers in your hosting platform:
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://www.datadoghq-browser-agent.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://browser-intake-datadoghq.com;Security Headers
Section titled “Security Headers”X-Frame-Options: DENYX-Content-Type-Options: nosniffX-XSS-Protection: 1; mode=blockReferrer-Policy: strict-origin-when-cross-originPermissions-Policy: geolocation=(), microphone=(), camera=()Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadHTTPS Only
Section titled “HTTPS Only”Always use HTTPS in production:
- GitHub Pages: Automatic
- Vercel: Automatic
- Netlify: Automatic
- Cloudflare: Automatic
- AWS: Configure ACM certificate
Rollback Procedure
Section titled “Rollback Procedure”GitHub Pages
Section titled “GitHub Pages”# Revert last commitgit revert HEADgit push origin main
# Or deploy specific versiongit checkout <commit-hash>git push -f origin mainVercel
Section titled “Vercel”# Via CLIvercel rollback
# Via dashboard# Deployments > Select previous > Promote to ProductionNetlify
Section titled “Netlify”# Via dashboard# Deploys > Select previous > Publish deployMaintenance
Section titled “Maintenance”Regular Updates
Section titled “Regular Updates”# Update dependencies monthlynpm updatenpm audit fix
# Test after updatesnpm run buildnpm run preview
# Commit and deploygit add package.json package-lock.jsongit commit -m "Update dependencies"git pushContent Updates
Section titled “Content Updates”# Add new page# Update sidebar# Edit: docs/astro.config.mjs
# Test locallynpm run dev
# Deploygit add .git commit -m "Add new documentation page"git push