/ astro-integrations / How to Use Railway with Astro: Complete Guide
astro-integrations 9 min read

How to Use Railway with Astro: Complete Guide

Step-by-step guide to integrating Railway with your Astro website.

How to Use Railway with Astro: Complete Guide

Railway is an infrastructure platform that makes deploying web applications surprisingly simple. Unlike static-only hosts, Railway gives you a full server environment with databases, cron jobs, and persistent storage. This makes it a great fit for Astro projects that use SSR, need a database, or run server-side logic alongside your frontend.

The setup takes about five minutes. You connect your repo, Railway detects your framework, and it deploys. No Dockerfiles, no YAML configs, no manual server provisioning.

A quick note on versions before we start. This guide was checked against Astro 6.4.2 and @astrojs/node 10.1.2, the current releases as of late May 2026. Astro is on v6 now, and a few things changed since older tutorials were written. The biggest one is that the output: 'hybrid' mode was removed back in Astro 5. Static is the default output, and you opt individual routes into on-demand rendering instead. The configuration section below reflects the current approach.

Prerequisites

  • Node.js v22.12.0 or higher (Astro 6 requires v22.12.0+; odd-numbered releases like v23 are not supported)
  • An Astro project (npm create astro@latest)
  • A Railway account (the free trial includes a one-time credit; ongoing usage is metered, with the Hobby plan starting at $5/month)
  • A Git repository on GitHub, or the Railway CLI installed locally

Installation

By default, Railway's build system (Railpack) builds an Astro project as a fully static site, and no adapter is required. If your Astro project is purely static, you can deploy it as is.

To server-render routes on demand (SSR, server islands, Astro actions, sessions, API endpoints), install the Node.js adapter:

npx astro add node

This installs @astrojs/node (currently 10.1.2, which lists astro ^6.3.0 as a peer dependency) and updates your astro.config.mjs to register the adapter.

Configuration

The Node adapter has two modes. Use standalone mode for Railway, since it builds a self-starting HTTP server that you run directly. The middleware mode is only for embedding Astro inside an existing Node HTTP server such as Express.

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

export default defineConfig({
  // 'static' (default) prerenders everything.
  // 'server' renders every page on demand. Note: 'hybrid' was
  // removed in Astro 5 and is no longer a valid value.
  output: "server",
  adapter: node({
    mode: "standalone",
  }),
});

If you want a mostly static site with only a few server-rendered routes, leave output as the default (static) and opt specific pages or endpoints into on-demand rendering by adding export const prerender = false at the top of that file. The rest of the site stays prerendered. This is the replacement for the old hybrid mode.

Add a start script to your package.json that Railway will use:

{
  "scripts": {
    "dev": "astro dev",
    "build": "astro build",
    "start": "node ./dist/server/entry.mjs"
  }
}

In standalone mode the adapter writes its entry point to ./dist/server/entry.mjs by default, and running that file boots the HTTP server.

There is one configuration detail that trips up almost everyone deploying Astro to Railway. Your app must listen on 0.0.0.0 (or ::), not on localhost, or Railway's proxy cannot reach it and you get a 502 error. The standalone server reads the HOST and PORT environment variables at runtime, so the cleanest fix is to set them in your start command:

{
  "scripts": {
    "start": "HOST=0.0.0.0 node ./dist/server/entry.mjs"
  }
}

Railway injects PORT automatically, and the standalone server picks it up, so you do not need to set the port yourself. You can also bind the host in astro.config.mjs via server: { host: true } if you prefer config over a runtime variable.

Basic Usage

There are two common paths. The dashboard path connects a GitHub repo:

  1. Go to railway.com and click "New Project"
  2. Select "Deploy from GitHub repo"
  3. Pick your Astro repository
  4. Railway auto-detects the build with Railpack and starts deploying

Railway runs npm run build and then npm run start by default. Your site will be live on a .railway.app subdomain within a couple of minutes. If a domain was not generated automatically, open the service's Networking settings and generate one.

The CLI path deploys straight from your machine. Install the CLI and ship:

npm i -g @railway/cli
railway login
railway init
railway up
railway domain

railway login authenticates through the browser, railway init scaffolds and links a project to your local directory, railway up uploads and deploys, and railway domain generates a public service domain.

To add environment variables, click on your service in Railway's dashboard and go to the Variables tab:

PUBLIC_SITE_URL=https://your-app.railway.app
DATABASE_URL=postgresql://user:pass@host:5432/db

One of Railway's strengths is adding services. Need a database? Click "New Service" > "Database" and pick PostgreSQL, MySQL, Redis, or MongoDB. Railway provisions it and gives you the connection string automatically. The example below uses the pg driver (currently 8.21.0); install it with npm install pg.

// src/lib/db.ts
// Railway injects DATABASE_URL as an environment variable
import pg from "pg";

const pool = new pg.Pool({
  connectionString: import.meta.env.DATABASE_URL,
});

export default pool;

Production Tips

  1. Use a custom domain. In your service settings, go to the Networking tab and add your custom domain. Railway provisions SSL automatically. Point your DNS A or CNAME record to the provided address.

  2. Set up health checks. Railway can restart your service if it becomes unresponsive. Add a simple health endpoint to your Astro API routes and configure the health check URL in your service settings.

  • Monitor resource usage. Railway charges based on CPU, memory, and network usage. Check your usage dashboard regularly, especially early on, to avoid surprises. Most Astro sites use minimal resources.

  • Use Railway's built-in cron jobs. If you need scheduled tasks like rebuilding a search index or sending emails, Railway supports cron services. Create a separate service with a cron schedule instead of building it into your main app.

  • Enable automatic deploys from a specific branch. By default, Railway deploys on every push to your main branch. You can change this to deploy only from a production branch, keeping your main branch for development.

  • Alternatives to Consider

    • Netlify or Vercel if your Astro site is mostly static and you want free hosting with a generous free tier and zero server management.
    • Fly.io if you need to run your application in specific geographic regions for latency-sensitive use cases.
    • Render if you want a similar platform-as-a-service experience with a slightly different pricing model and a free tier for web services.

    Common Errors and Fixes

    502 Bad Gateway / "Application failed to respond." This is the single most common Railway and Astro issue. Your app needs to listen on 0.0.0.0 or :: to accept traffic from Railway's proxy. A standalone Node-adapter server bound to localhost will return a 502. Fix it by starting with HOST=0.0.0.0 node ./dist/server/entry.mjs, or set server: { host: true } in astro.config.mjs. Railway's own Astro guide calls this out explicitly.

    The port your app listens on is ignored. The standalone server reads the PORT environment variable at runtime, and Railway sets PORT for you. Do not hardcode a port in your config and expect it to win. If you must override it locally, pass it on the command line as PORT=4321 node ./dist/server/entry.mjs.

    output: 'hybrid' is not a valid configuration value. It was removed in Astro 5, so any tutorial that still uses it predates the current API and will error on Astro 6. Use static (the default) or server, and opt individual routes into on-demand rendering with export const prerender = false.

    The deploy builds a static site even though you wanted SSR. Railpack builds Astro as a static site by default. On-demand rendering only happens once you add the Node adapter and either set output: 'server' or opt routes out of prerendering. If your dynamic routes 404 or serve stale HTML, confirm the adapter is registered in astro.config.mjs.

    Unsupported Node version. Astro 6 requires Node v22.12.0 or higher. Odd-numbered releases like v23 are not supported. If the build fails on a version error, pin a supported version (for example with a .nvmrc or the engines field in package.json).

    Official Docs and Examples

    Wrapping Up

    Railway is the right choice when your Astro project needs more than static hosting. Database connections, server-side rendering, background jobs, and custom server logic all work out of the box. The developer experience is polished, the pricing is metered and transparent, and you can go from code to production in minutes. Just remember the two things that bite people: bind to 0.0.0.0, and use server output with the Node adapter rather than the long-gone hybrid mode.

    Sources

    Checked on 2026-05-29.