Skip to content
All essays
WebMarch 27, 202614 min

Astro Deployment Guide: Production-Ready Hosting Strategies

Complete guide to deploying Astro applications to various platforms including Vercel, Netlify, Cloudflare, and Node.js servers.

Ü
Ümit Uz
Mobile & Full Stack Developer

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:

  1. 1Static (Static Site Generation): Pre-rendered HTML/CSS/JS
  2. 2Server (Server-Side Rendering): Dynamic rendering on each request
  3. 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

bash
# Build your Astro project
npm run build

# Output in /dist directory
# Deploy the /dist folder

Vercel Deployment

bash
# Install Vercel CLI
npm i -g vercel

# Deploy
vercel --prod
json
// vercel.json
{
  "buildCommand": "npm run build",
  "outputDirectory": "dist",
  "devCommand": "npm run dev"
}

Netlify Deployment

bash
# Install Netlify CLI
npm i -g netlify-cli

# Deploy
netlify deploy --prod
toml
# netlify.toml
[build]
  command = "npm run build"
  publish = "dist"

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

Cloudflare Pages Deployment

bash
# Install Wrangler CLI
npm install -g wrangler

# Deploy
wrangler pages publish dist
toml
# 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

javascript
// astro.config.mjs
import { defineConfig } from 'astro/config';

export default defineConfig({
  output: 'server',
  adapter: node({
    mode: 'standalone',
  }),
});

Vercel Deployment (SSR)

bash
npm install @astrojs/vercel
javascript
// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel';

export default defineConfig({
  output: 'server',
  adapter: vercel(),
});

Netlify Deployment (SSR)

bash
npm install @astrojs/netlify
javascript
// astro.config.mjs
import { defineConfig } from 'astro/config';
import netlify from '@astrojs/netlify';

export default defineConfig({
  output: 'server',
  adapter: netlify(),
});

Cloudflare Deployment (SSR)

bash
npm install @astrojs/cloudflare
javascript
// 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

javascript
// astro.config.mjs
import { defineConfig } from 'astro/config';
import hybrid from '@astrojs/netlify';

export default defineConfig({
  output: 'hybrid',
  adapter: hybrid(),
});

Define Prerender Routes

javascript
// src/pages/prerender.ts
export function prerender() {
  return true;
}

Node.js Deployment

Deploy to your own Node.js server.

Standalone Build

javascript
// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';

export default defineConfig({
  output: 'server',
  adapter: node({
    mode: 'standalone',
  }),
});

Express Integration

javascript
// 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
# 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

yaml
# 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

bash
# .env
DATABASE_URL=postgresql://localhost:5432/mydb
API_SECRET=development-secret

Production

bash
# Set environment variables in hosting platform
DATABASE_URL=postgresql://production-db:5432/mydb
API_SECRET=production-secret

Access in Astro

javascript
// 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

yaml
# .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

javascript
// astro.config.mjs
export default defineConfig({
  build: {
    assets: '_astro',
  },
  vite: {
    build: {
      rollupOptions: {
        output: {
          assetFileNames: '_astro/[hash].[ext]',
        },
      },
    },
  },
});

Compression

javascript
// 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

javascript
// 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

javascript
// 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

javascript
// 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

javascript
// 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

javascript
// 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

bash
# Deploy previous commit
git checkout HEAD~1
npm run build
vercel --prod

Zero-Downtime Deployment

yaml
# Deploy new version alongside old
# Switch traffic when healthy
# Gradually phase out old version

Scaling Considerations

Plan for application scaling.

Horizontal Scaling

javascript
// Use stateless design
// Store sessions in Redis
// Use load balancer
// Implement health checks

Vertical Scaling

javascript
// Optimize database queries
// Implement caching
// Use connection pooling
// Monitor resource usage

Best Practices

1. Use Environment-Specific Configs

javascript
// astro.config.mjs
export default defineConfig({
  site: import.meta.env.SITE_URL,
});

2. Implement Proper Error Handling

javascript
// 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

javascript
// Set up analytics
// Monitor Core Web Vitals
// Track error rates
// Monitor uptime

4. Automate Deployments

yaml
# Use CI/CD
# Run tests before deploy
# Automated rollback on failure
# Blue-green deployment

Conclusion

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:

  1. 1Choose the right deployment mode (static, server, hybrid)
  2. 2Use appropriate adapters for your hosting platform
  3. 3Implement proper environment variable management
  4. 4Set up CI/CD pipelines for automation
  5. 5Monitor performance and errors
  6. 6Plan for scaling and rollbacks
  7. 7Follow security best practices

With these deployment strategies, your Astro applications will be production-ready, scalable, and performant.

Enjoyed this essay? Share it.

Related essays

Next essay
SolidJS Fundamentals: A Complete Guide to Modern Reactive UI Development