Astro is a modern web framework designed for content-driven websites. It delivers best-in-class performance by shipping zero JavaScript to the browser by default, using its island architecture to hydrate only the interactive components that need it. Astro supports multiple UI frameworks including React, Vue, Svelte, and Solid — all in the same project.
With Out Plane, you can deploy your Astro application in under a minute — directly from your GitHub repository. This guide shows you exactly how.
What You'll Need
Before starting, make sure you have:
- Node.js 20+ installed on your machine
- npm (comes with Node.js)
- A GitHub account
- An Astro application in a GitHub repository
Don't have Node.js installed? Download it from nodejs.org:
- Windows: Download the LTS installer from nodejs.org
- macOS: Use
brew install nodeor download from nodejs.org - Linux: Run
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - && sudo apt install -y nodejs(Ubuntu/Debian)
Once Node.js is installed, create a new Astro project:
npm create astro@latest my-astro-app
cd my-astro-appIf you don't have an Astro app yet, use our example below.
Quick Start: Sample Astro Application
Here's a minimal Astro application with SSR support. Create a new project:
npm create astro@latest my-astro-app
cd my-astro-appInstall the Node.js adapter for server-side rendering:
npx astro add nodeThis installs @astrojs/node and updates your configuration automatically. Verify your astro.config.mjs looks like this:
import { defineConfig } from "astro/config";
import node from "@astrojs/node";
export default defineConfig({
output: "server",
adapter: node({
mode: "standalone",
}),
server: {
host: "0.0.0.0",
port: 4321,
},
});The output: "server" setting enables SSR, and the Node adapter with mode: "standalone" creates a self-contained server you can run with Node.js.
Replace src/pages/index.astro with a simple page:
---
const title = "My Astro App";
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>{title}</title>
</head>
<body>
<main style="padding: 2rem; font-family: system-ui;">
<h1>Hello from Astro!</h1>
<p>Deployed on Out Plane</p>
<p>Built at: {new Date().toISOString()}</p>
</main>
</body>
</html>Add a health check API endpoint at src/pages/api/health.ts:
import type { APIRoute } from "astro";
export const GET: APIRoute = () => {
return new Response(JSON.stringify({ status: "healthy" }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
};Create a Dockerfile in the project root:
FROM node:20-alpine AS base
# Install dependencies
FROM base AS deps
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci
# Build the application
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Production image
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 astro
RUN adduser --system --uid 1001 astro
COPY --from=builder --chown=astro:astro /app/dist ./dist
COPY --from=builder --chown=astro:astro /app/node_modules ./node_modules
USER astro
EXPOSE 4321
ENV HOST=0.0.0.0
ENV PORT=4321
CMD ["node", "dist/server/entry.mjs"]Push this code to a GitHub repository, and you're ready to deploy.
Deploy in 3 Steps
Step 1: Connect Your Repository
- Go to console.outplane.com
- Sign in with your GitHub account
- Select your Astro repository from the list
Out Plane automatically detects your application and configures the build process.
Step 2: Configure Your Application
Configure the following settings in the create application form:
Build Method
Select how Out Plane should build your application:
- Dockerfile (Recommended for SSR): Uses the multi-stage Dockerfile above for optimal image size and server-side rendering support.
- Buildpacks: Automatically detects Node.js and runs
npm run build. Works for simpler Astro applications.
For production Astro applications with SSR, Dockerfile with the Node adapter is the recommended approach.
Basic Settings
- Port: Set to
4321 - Branch: Select
mainor your preferred branch - Region: Choose the region closest to your users
Environment Variables (Optional)
If your application uses environment-specific configuration, add them here. Astro uses two types of environment variables:
- Server-only: Standard variables like
DATABASE_URL,API_SECRET - Client-exposed: Prefixed with
PUBLIC_to be available in the browser
Add variables using the Add button or Raw Edit for bulk entry:
DATABASE_URL=postgres://user:password@host/database
API_SECRET=your-api-secret
PUBLIC_SITE_URL=https://your-app.outplane.appStep 3: Deploy
Click Deploy Application and watch the build process:
- Queued → Waiting for resources
- Building → Installing dependencies, running
astro build - Deploying → Starting your Astro application
- Ready → Your app is live
Once the status shows Ready, your application is live. You can find your application URL at the top of the deployment page. Click the URL to open your Astro app in a new tab. SSL is automatically configured.
Production Best Practices
SSR vs Static Output
Astro supports multiple output modes. Choose based on your needs:
output: "static"(default): Pre-renders all pages at build time. Best for content sites that don't need dynamic data. No server required.output: "server": Server-side renders all pages on each request. Best for dynamic applications with authentication or personalized content.output: "hybrid": Static by default, with opt-in SSR for specific pages usingexport const prerender = false. Best balance for most applications.
For static output, you can use Buildpacks without the Node adapter. For server or hybrid output, use the Dockerfile approach with @astrojs/node.
Island Architecture
Astro's island architecture lets you use interactive UI components only where needed. Components are static HTML by default and only hydrate when you add a client:* directive:
---
import Counter from "../components/Counter.tsx";
import Header from "../components/Header.astro";
---
<!-- Static HTML, zero JavaScript -->
<Header />
<!-- Interactive island, hydrates on page load -->
<Counter client:load />
<!-- Interactive island, hydrates when visible -->
<Counter client:visible />This approach sends significantly less JavaScript to the browser compared to traditional SPA frameworks.
Image Optimization
Astro includes built-in image optimization. Use the <Image /> component for automatic format conversion and resizing:
---
import { Image } from "astro:assets";
import heroImage from "../assets/hero.png";
---
<Image src={heroImage} alt="Hero image" width={800} />For remote images, configure allowed domains in astro.config.mjs:
export default defineConfig({
image: {
remotePatterns: [
{ protocol: "https", hostname: "your-cdn.com" },
],
},
});Content Collections
Use Astro's content collections for type-safe content management. Define a collection schema in src/content/config.ts:
import { defineCollection, z } from "astro:content";
const blog = defineCollection({
type: "content",
schema: z.object({
title: z.string(),
date: z.date(),
description: z.string(),
draft: z.boolean().default(false),
}),
});
export const collections = { blog };Content collections provide built-in validation, TypeScript types, and query APIs for your Markdown and MDX content.
View Transitions
Astro supports the View Transitions API for smooth page transitions without client-side JavaScript overhead:
---
import { ViewTransitions } from "astro:transitions";
---
<html>
<head>
<ViewTransitions />
</head>
<body>
<slot />
</body>
</html>This gives your multi-page application a single-page app feel while maintaining the performance benefits of server-rendered HTML.
Connecting a Database
Most dynamic Astro applications need a database. Out Plane provides managed PostgreSQL:
- Go to Databases in the sidebar
- Click Create Database
- Select PostgreSQL version and region
- Copy the connection URL
Add the connection URL as an environment variable:
DATABASE_URL=postgres://user:password@host/databaseUse it in your Astro application with Drizzle ORM:
// src/lib/db.ts
import { drizzle } from "drizzle-orm/node-postgres";
import pg from "pg";
const pool = new pg.Pool({
connectionString: import.meta.env.DATABASE_URL,
});
export const db = drizzle(pool);Define a schema and query it in your pages:
// src/lib/schema.ts
import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";
export const posts = pgTable("posts", {
id: serial("id").primaryKey(),
title: text("title").notNull(),
content: text("content").notNull(),
createdAt: timestamp("created_at").defaultNow(),
});---
// src/pages/posts.astro
import { db } from "../lib/db";
import { posts } from "../lib/schema";
const allPosts = await db.select().from(posts);
---
<ul>
{allPosts.map((post) => (
<li>{post.title}</li>
))}
</ul>Custom Domain Setup
Replace the default .outplane.app URL with your own domain:
- Navigate to Domains
- Click Map Domain
- Enter your domain (e.g.,
app.yourdomain.com) - Add the DNS records shown to your domain registrar
Update your PUBLIC_SITE_URL environment variable to reflect the new domain. SSL certificates are automatically provisioned once DNS propagates.
Monitoring Your Application
After deployment, monitor your Astro application:
- Logs: View real-time application logs including server-side rendering logs
- Metrics: Track CPU, memory, and network usage
- HTTP Logs: Analyze incoming requests, response times, and status codes
Access these from the sidebar in your application dashboard.
Troubleshooting
Adapter Not Configured
Install the Node adapter. SSR deployments require @astrojs/node. Run npx astro add node and verify your astro.config.mjs includes the adapter:
import node from "@astrojs/node";
export default defineConfig({
output: "server",
adapter: node({ mode: "standalone" }),
});Without the adapter, astro build will not produce a server entry point and the container will fail to start.
Static vs Server Output Confusion
Check your output mode. If you set output: "static" but use server-only features like API endpoints with POST handlers or Astro.cookies, the build will fail. Switch to output: "server" or output: "hybrid" for dynamic features.
Conversely, if your site is fully static, remove the Node adapter and use output: "static" with Buildpacks for simpler deployments.
Environment Variables Not Accessible
Use import.meta.env instead of process.env. Astro uses Vite under the hood. Access environment variables with:
// Server-side (available in .astro files and API routes)
const dbUrl = import.meta.env.DATABASE_URL;
// Client-side (must be prefixed with PUBLIC_)
const siteUrl = import.meta.env.PUBLIC_SITE_URL;Variables without the PUBLIC_ prefix are only available on the server.
Build Errors with Dependencies
Check Node.js compatibility. Some npm packages require specific Node.js versions. Verify your package.json includes an engines field:
{
"engines": {
"node": ">=20.0.0"
}
}If using native dependencies, make sure your Dockerfile uses a compatible base image like node:20-alpine with libc6-compat.
Hydration Mismatch Errors
Ensure client components receive serializable props. When using client:load or client:visible directives, all props passed to the component must be serializable (strings, numbers, booleans, plain objects). Functions, Dates, and class instances cannot be passed as props to client-side islands.
---
import Counter from "../components/Counter.tsx";
---
<!-- Good: serializable prop -->
<Counter initialCount={5} client:load />
<!-- Bad: non-serializable prop -->
<Counter onCount={() => console.log("clicked")} client:load />Next Steps
Your Astro application is now deployed and running in production. Here's what to explore next:
- Scale your application: Adjust instance types and auto-scaling settings for higher traffic
- Set up CI/CD: Enable automatic deployments on every git push
- Add monitoring: Integrate with external monitoring tools via Out Plane's metrics export
- Add integrations: Install Astro integrations for Tailwind, MDX, Sitemap, and more from the Astro ecosystem
Summary
Deploying an Astro application to Out Plane takes three steps:
- Connect your GitHub repository
- Configure port (4321), environment variables, and build method
- Deploy and get your live URL with automatic HTTPS
No server configuration, no manual SSL setup, no infrastructure management. Full support for server-side rendering, island architecture, and content collections.
Ready to deploy your Astro application? Get started with Out Plane and receive $20 in free credit.