Last checked with Wasp 0.23 and Railway (as of Apr 6, 2026).
This guide depends on external libraries or services, so it may become outdated over time. We do our best to keep it up to date, but make sure to check their documentation for any changes.Railway
Automatic Deployment server client database
We recommend that you use Wasp Deploy to deploy your Wasp app to Railway. Wasp CLI automates deploying the client, the server and the database with one command.
Manual Deployment server client database
This guide shows you how to deploy the client, the server, and provision a database on Railway.
Prerequisites
To get started, follow these steps:
- Make sure your Wasp app is built by running
wasp buildin the project dir. - Create a Railway account.
- Install the Railway CLI.
- Run
railway loginand a browser tab will open to authenticate you.
Create New Project
Let's create our Railway project:
- Go to your Railway dashboard, click on New Project, and select Deploy PostgreSQL from the dropdown menu.
- Once the project is created, left-click on the Create button in the top right corner and select Empty Service.
- Click on the new service, and change the name to
server. - Create another empty service and name it
client. - Deploy the changes by pressing the Deploy button on top.
Deploy Your App to Railway
Setup Domains
We'll need the domains for both the server and client services:
- Go to the
serverinstance's Settings tab, and click Generate Domain. - Enter
8080as the port and click Generate Domain. - Do the same under the
client's Settings. - Copy both domains, as we will need them later.
Deploying the Server
You'll deploy the server first:
-
Move into the
.wasp/outdirectory:cd .wasp/out -
Link the
.wasp/outdirectory to your newly created Railway project:railway linkSelect
serverwhen prompted to select a service. -
Go into the Railway dashboard and set up the required env variables:
Click on the
serverservice and go to the Variables tab:-
Click Variable reference and select
DATABASE_URL(it will populate it with the correct value) -
Add
WASP_WEB_CLIENT_URLwith theclientdomain (e.g.https://client-production-XXXX.up.railway.app).https://prefix is required! -
Add
WASP_SERVER_URLwith theserverdomain (e.g.https://server-production-XXXX.up.railway.app).https://prefix is required! -
Add
JWT_SECRETwith a random string at least 32 characters long
-
-
Push and deploy the project:
railway up --ciWe use the
--ciflag to limit the log output to only the build process.Railway will locate the
Dockerfilein.wasp/outand deploy your server.
Deploying the Client
-
Create the production build from the project root, using the
serverdomain as theREACT_APP_API_URL:REACT_APP_API_URL=<url_to_wasp_backend> npx vite build -
Create a
railway.jsonfile in.wasp/out/web-app/buildto ensure Railway uses the correct builder for the static files:.wasp/out/web-app/build/railway.json{
"$schema": "https://railway.com/railway.schema.json",
"build": {
"builder": "RAILPACK"
}
} -
Create a
Caddyfilein.wasp/out/web-app/buildto configure how Railway serves your static files:.wasp/out/web-app/build/Caddyfile{
admin off
persist_config off
auto_https off
log {
format json
}
servers {
trusted_proxies static private_ranges
}
}
:{$PORT:80} {
log {
format json
}
respond /health 200
# Security headers
header {
# Enable cross-site filter (XSS) and tell browsers to block detected attacks
X-XSS-Protection "1; mode=block"
# Prevent some browsers from MIME-sniffing a response away from the declared Content-Type
X-Content-Type-Options "nosniff"
# Keep referrer data off of HTTP connections
Referrer-Policy "strict-origin-when-cross-origin"
# Enable strict Content Security Policy
Content-Security-Policy "default-src 'self'; img-src 'self' data: https: *; style-src 'self' 'unsafe-inline' https: *; script-src 'self' 'unsafe-inline' https: *; font-src 'self' data: https: *; connect-src 'self' https: *; media-src 'self' https: *; object-src 'none'; frame-src 'self' https: *;"
# Remove Server header
-Server
}
root * .
# Handle static files
file_server {
hide .git
hide .env*
}
# Compression with more formats
encode {
gzip
zstd
}
# Try files with HTML extension and handle SPA routing
# This is where we diverge from the Railpacks's original Caddyfile
try_files {path} {path}/index.html /200.html
handle_errors {
rewrite * /{err.status_code}.html
file_server
}
}This overrides Railway's default Caddyfile so that prerendered pages are served correctly and non-prerendered routes fall back to the SPA shell (
200.html). -
Link the client build directory to the
clientservice:cd .wasp/out/web-app/build
railway link -
Deploy the client build to Railway:
railway up --ciSelect
clientwhen prompted to select a service.
And now your Wasp should be deployed!
Back in your Railway dashboard, click on your project and you should see your newly deployed services: PostgreSQL, Server, and Client.
Updates & Redeploying
When you make updates and need to redeploy:
-
Run
wasp buildto rebuild your app. -
Go into the
.wasp/outdirectory and:Deploy the server with:
railway up --ci -
Rebuild the client from the project root:
REACT_APP_API_URL=<url_to_wasp_backend> npx vite buildAnd then deploy the client with:
cd .wasp/out/web-app/build
railway up --ci