Deploying Astro applications requires understanding your project's architecture and choosing the right hosting strategy. This comprehensive guide covers deployment options for static sites, server-side rendering, and hybrid applications.
Understanding Astro Deployment Modes
Astro supports multiple deployment modes:
- 1Static (Static Site Generation): Pre-rendered HTML/CSS/JS
- 2Server (Server-Side Rendering): Dynamic rendering on each request
- 3Hybrid: Mix of static and server-rendered routes
Static Site Deployment
Static sites are pre-built and deployed to CDN edge servers.
Build for Production
# Build your Astro project
npm run build
# Output in /dist directory
# Deploy the /dist folderVercel Deployment
# Install Vercel CLI
npm i -g vercel
# Deploy
vercel --prod// vercel.json
{
"buildCommand": "npm run build",
"outputDirectory": "dist",
"devCommand": "npm run dev"
}Netlify Deployment
# Install Netlify CLI
npm i -g netlify-cli
# Deploy
netlify deploy --prod# netlify.toml
[build]
command = "npm run build"
publish = "dist"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200Cloudflare Pages Deployment
# Install Wrangler CLI
npm install -g wrangler
# Deploy
wrangler pages publish dist# wrangler.toml
name = "astro-project"
compatibility_date = "2024-01-01"
[env.production]
vars = { ENVIRONMENT = "production" }Server-Side Rendering Deployment
SSR applications need a Node.js server runtime.
Configure for SSR
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
output: 'server',
adapter: node({
mode: 'standalone',
}),
});Vercel Deployment (SSR)
npm install @astrojs/vercel// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel';
export default defineConfig({
output: 'server',
adapter: vercel(),
});Netlify Deployment (SSR)
npm install @astrojs/netlify// astro.config.mjs
import { defineConfig } from 'astro/config';
import netlify from '@astrojs/netlify';
export default defineConfig({
output: 'server',
adapter: netlify(),
});Cloudflare Deployment (SSR)
npm install @astrojs/cloudflare// astro.config.mjs
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
output: 'server',
adapter: cloudflare(),
});Hybrid Deployment
Mix static and server-rendered routes.
Configure Hybrid Mode
// astro.config.mjs
import { defineConfig } from 'astro/config';
import hybrid from '@astrojs/netlify';
export default defineConfig({
output: 'hybrid',
adapter: hybrid(),
});Define Prerender Routes
// src/pages/prerender.ts
export function prerender() {
return true;
}Node.js Deployment
Deploy to your own Node.js server.
Standalone Build
// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
export default defineConfig({
output: 'server',
adapter: node({
mode: 'standalone',
}),
});Express Integration
// server.js
import express from 'express';
import { handler as ssrHandler } from './dist/server/entry.mjs';
const app = express();
// Serve static files
app.use(express.static('dist/client'));
// Handle all other requests with Astro
app.use(ssrHandler);
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});Docker Deployment
Containerize your Astro application.
Dockerfile
# Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["node", "./server.js"]Docker Compose
# docker-compose.yml
version: '3.8'
services:
astro:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://...Environment Variables
Manage environment variables for different environments.
Local Development
# .env
DATABASE_URL=postgresql://localhost:5432/mydb
API_SECRET=development-secretProduction
# Set environment variables in hosting platform
DATABASE_URL=postgresql://production-db:5432/mydb
API_SECRET=production-secretAccess in Astro
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
vite: {
define: {
'import.meta.env.DATABASE_URL': JSON.stringify(process.env.DATABASE_URL),
},
},
});CI/CD Pipeline
Automate deployment with continuous integration.
GitHub Actions
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
- name: Deploy to Vercel
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.ORG_ID }}
vercel-project-id: ${{ secrets.PROJECT_ID }}Performance Optimization
Optimize deployment for performance.
CDN Configuration
// astro.config.mjs
export default defineConfig({
build: {
assets: '_astro',
},
vite: {
build: {
rollupOptions: {
output: {
assetFileNames: '_astro/[hash].[ext]',
},
},
},
},
});Compression
// server.js
import compression from 'compression';
import express from 'express';
import { handler as ssrHandler } from './dist/server/entry.mjs';
const app = express();
// Enable compression
app.use(compression());
app.use(express.static('dist/client'));
app.use(ssrHandler);
app.listen(3000);Monitoring and Logging
Set up monitoring for production deployments.
Error Tracking
// src/scripts/sentry.js
import * as Sentry from '@sentry/astro';
Sentry.init({
dsn: import.meta.env.SENTRY_DSN,
environment: import.meta.env.MODE,
});Analytics Integration
// src/components/Analytics.astro
---
const GA_ID = import.meta.env.GA_ID;
---
<script is:inline>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '{GA_ID}');
</script>
<script async src="https://www.googletagmanager.com/gtag/js?id={GA_ID}"></script>Security Best Practices
Secure your deployed application.
Headers Configuration
// astro.config.mjs
export default defineConfig({
vite: {
plugins: [
{
name: 'security-headers',
transform(html, id) {
if (id.endsWith('.html')) {
return {
html: html.replace(
'</head>',
`<meta http-equiv="Content-Security-Policy" content="default-src 'self';"></head>`
),
};
}
},
},
],
},
});Rate Limiting
// server.js
import rateLimit from 'express-rate-limit';
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
});
app.use('/api/', limiter);Database Migrations
Handle database migrations on deployment.
Migration Script
// scripts/migrate.js
import { Client } from 'pg';
const client = new Client({
connectionString: process.env.DATABASE_URL,
});
await client.connect();
// Run migrations
await client.query(`
CREATE TABLE IF NOT EXISTS posts (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT
);
`);
await client.end();
console.log('Migrations completed');Rollback Strategy
Plan for deployment rollbacks.
Git-Based Rollback
# Deploy previous commit
git checkout HEAD~1
npm run build
vercel --prodZero-Downtime Deployment
# Deploy new version alongside old
# Switch traffic when healthy
# Gradually phase out old versionScaling Considerations
Plan for application scaling.
Horizontal Scaling
// Use stateless design
// Store sessions in Redis
// Use load balancer
// Implement health checksVertical Scaling
// Optimize database queries
// Implement caching
// Use connection pooling
// Monitor resource usageBest Practices
1. Use Environment-Specific Configs
// astro.config.mjs
export default defineConfig({
site: import.meta.env.SITE_URL,
});2. Implement Proper Error Handling
// src/pages/api/data.ts
export async function GET() {
try {
const data = await fetchData();
return new Response(JSON.stringify(data));
} catch (error) {
return new Response(JSON.stringify({ error: 'Failed' }), {
status: 500,
});
}
}3. Monitor Performance
// Set up analytics
// Monitor Core Web Vitals
// Track error rates
// Monitor uptime4. Automate Deployments
# Use CI/CD
# Run tests before deploy
# Automated rollback on failure
# Blue-green deploymentConclusion
Deploying Astro applications requires understanding your project's needs and choosing the right deployment strategy. Whether you're deploying static sites to CDNs or server-rendered applications to Node.js servers, Astro provides flexible options for production-ready deployments.
Key takeaways:
- 1Choose the right deployment mode (static, server, hybrid)
- 2Use appropriate adapters for your hosting platform
- 3Implement proper environment variable management
- 4Set up CI/CD pipelines for automation
- 5Monitor performance and errors
- 6Plan for scaling and rollbacks
- 7Follow security best practices
With these deployment strategies, your Astro applications will be production-ready, scalable, and performant.