How to Deploy Strapi on Railway with PostgreSQL from Scratch
This guide explains how to create a Strapi project locally, push it to GitHub, deploy it on Railway, connect it to PostgreSQL, and access the Strapi admin panel online.
It is written for developers who want to use Strapi as a CMS backend for a Next.js website, technical blog, AI directory, or content-driven project.
Final Architecture
The final setup looks like this:
Frontend website:
aiseocode.com
Strapi CMS:
cms.aiseocode.com or Railway temporary domain
Backend hosting:
Railway
Database:
Railway PostgreSQL
Code repository:
GitHub
For a Next.js content website, a common production setup is:
Next.js frontend → Vercel
Strapi CMS → Railway
Database → Railway PostgreSQL
Media storage → Cloudflare R2, S3, or Cloudinary
Step 1: Check Node.js and npm
First, check your local Node.js and npm versions:
node -v
npm -v
git --version
Strapi 5 requires a supported Node.js version. If your Node.js version is too new, for example Node 25, Strapi may fail to create or run the project.
A safe choice is Node.js 22 LTS.
If you use nvm, install and switch to Node.js 22:
nvm install 22
nvm use 22
nvm alias default 22
Then confirm:
node -v
npm -v
You should see a Node.js version similar to:
v22.x.x
Step 2: Create a Local Strapi Project
Create a new Strapi project:
npx create-strapi-app@latest aiseocode-cms
During the setup, choose:
Login or sign up: Skip
Default database sqlite: Yes
Example structure and data: No
TypeScript: Yes
Install dependencies with npm: Yes
Initialize a git repository: Yes
For local development, SQLite is fine. Later, Railway will use PostgreSQL.
After installation, go into the project directory:
cd aiseocode-cms
Start Strapi locally:
npm run develop
Open the local admin panel:
http://localhost:1337/admin
Create your first local admin account.
Step 3: Push the Project to GitHub
After confirming Strapi works locally, commit the project:
git add .
git commit -m "init aiseocode strapi cms"
git branch -M main
Create a new GitHub repository, for example:
aiseocode-cms
Do not initialize the GitHub repository with a README, .gitignore, or license if your local repository already exists.
Then connect your local project to GitHub:
git remote add origin https://github.com/your-username/aiseocode-cms.git
git push -u origin main
Step 4: Install PostgreSQL Driver
Railway will use PostgreSQL in production, so install the PostgreSQL driver:
npm install pg
Commit and push the change:
git add .
git commit -m "add postgres driver"
git push
Step 5: Configure Strapi Database for Railway
Open the Strapi database configuration file:
nano config/database.ts
Replace the content with:
import path from 'path';
export default ({ env }) => {
const client = env('DATABASE_CLIENT', 'sqlite');
const connections = {
postgres: {
connection: {
connectionString: env('DATABASE_URL'),
host: env('DATABASE_HOST'),
port: env.int('DATABASE_PORT'),
database: env('DATABASE_NAME'),
user: env('DATABASE_USERNAME'),
password: env('DATABASE_PASSWORD'),
ssl: env.bool('DATABASE_SSL', false)
? {
rejectUnauthorized: env.bool('DATABASE_SSL_REJECT_UNAUTHORIZED', false),
}
: false,
},
pool: {
min: env.int('DATABASE_POOL_MIN', 2),
max: env.int('DATABASE_POOL_MAX', 10),
},
},
sqlite: {
connection: {
filename: path.join(
__dirname,
'..',
'..',
env('DATABASE_FILENAME', '.tmp/data.db')
),
},
useNullAsDefault: true,
},
};
return {
connection: {
client,
...connections[client],
acquireConnectionTimeout: env.int('DATABASE_CONNECTION_TIMEOUT', 60000),
},
};
};
This configuration allows:
Local development: SQLite
Railway production: PostgreSQL
Save the file, then test locally:
npm run develop
If it works, stop the server with:
Control + C
Then commit and push:
git add .
git commit -m "configure database for railway postgres"
git push
Step 6: Deploy Strapi on Railway
Go to Railway and create a new project.
Choose:
New Project
→ GitHub Repository
→ Select your Strapi repository
→ Deploy
Railway will pull your GitHub project and start building it.
At first, the service may crash because environment variables and PostgreSQL are not configured yet. This is normal.
Step 7: Add PostgreSQL on Railway
Inside the same Railway project, click:
+ Add
→ Database
→ PostgreSQL
After adding PostgreSQL, the Railway project should have two services:
aiseocode-cms
Postgres
Step 8: Add Environment Variables
Open the Strapi service:
aiseocode-cms
→ Variables
Add the following variables:
NODE_ENV=production
HOST=0.0.0.0
PORT=1337
DATABASE_CLIENT=postgres
DATABASE_URL=${{Postgres.DATABASE_URL}}
DATABASE_HOST=${{Postgres.PGHOST}}
DATABASE_PORT=${{Postgres.PGPORT}}
DATABASE_NAME=${{Postgres.PGDATABASE}}
DATABASE_USERNAME=${{Postgres.PGUSER}}
DATABASE_PASSWORD=${{Postgres.PGPASSWORD}}
DATABASE_SSL=false
DATABASE_SSL_REJECT_UNAUTHORIZED=false
If your PostgreSQL service is not named Postgres, replace Postgres with the actual service name.
Step 9: Add Strapi Secret Keys
Strapi also requires security keys.
Generate random keys locally:
openssl rand -base64 32
Run the command multiple times and fill these Railway variables:
APP_KEYS=key1,key2,key3,key4
API_TOKEN_SALT=key5
ADMIN_JWT_SECRET=key6
TRANSFER_TOKEN_SALT=key7
JWT_SECRET=key8
ENCRYPTION_KEY=key9
Important rules:
APP_KEYS should contain multiple keys separated by English commas.
Do not use quotes.
Do not keep placeholder values such as "tobemodified".
Step 10: Apply Changes and Redeploy
After adding variables, Railway may show:
Apply changes
Click it and deploy the changes.
Wait until the service status becomes:
Online
Step 11: Open the Strapi Admin Panel
Generate a public Railway domain from:
Settings
→ Networking
→ Generate Domain
Then open:
https://your-railway-domain.up.railway.app/admin
If you see the Strapi admin registration page, the deployment is successful.
Create the production admin account.
Your local admin account and Railway admin account are separate because they use different databases.
Step 12: Create an Article Content Type Locally
Strapi content types should be created locally in development mode, then committed to GitHub.
Start Strapi locally:
cd /Users/your-name/aiseocode-cms
npm run develop
Open:
http://localhost:1337/admin
Go to:
Content-Type Builder
→ Create new collection type
Create:
Display name: Article
Enable Internationalization if your project needs multiple languages.
Step 13: Add Article Fields
Create these fields:
title
slug
content
Recommended settings:
| Field | Type | Required | Unique | Localization |
|---|---|---:|---:|---:|
| title | Text | Yes | No | Yes |
| slug | Text | Yes | Yes | Yes |
| content | Rich Text | Yes | No | Yes |
Use Text for slug if you want to write the slug manually.
Do not use UID if you do not want Strapi to generate the slug from the title.
For the slug field, you may add this regular expression:
^[a-z0-9]+(?:-[a-z0-9]+)*$
This allows slugs like:
deploy-strapi-railway-postgresql
nextjs-strapi-blog
ai-seo-tools
Step 14: Add Chinese Locale
In Strapi, go to:
Settings
→ Internationalization
→ Locales
→ Add new locale
Choose:
Chinese (Simplified, China) (zh-CN)
Keep:
Set as default locale: false
The recommended language structure is:
Default language: English
Chinese language: zh-CN
Your frontend URL structure can be:
English:
https://aiseocode.com/article/deploy-strapi-railway-postgresql
Chinese:
https://aiseocode.com/zh-cn/article/deploy-strapi-railway-postgresql-zh-cn
Step 15: Commit the Article Content Type
After saving the content type locally, stop Strapi:
Control + C
Then commit and push:
git status
git add .
git commit -m "add article content type and zh-cn locale"
git push
Railway will automatically redeploy.
After deployment, the online Strapi admin should show the Article collection type.
Step 16: Create a Test Article Online
Open the online Strapi admin:
https://your-railway-domain.up.railway.app/admin
Go to:
Content Manager
→ Article
→ Create new entry
Create an English article:
title: Test Article
slug: test-article
content: This is a test article.
Save and publish it.
Step 17: Enable Public API Access
If the API returns permission errors, go to:
Settings
→ Users & Permissions Plugin
→ Roles
→ Public
Enable these permissions for Article:
find
findOne
Save.
Then test:
https://your-railway-domain.up.railway.app/api/articles
If JSON data appears, Strapi is working correctly.
Step 18: Bind a Custom Domain
After the Railway temporary domain works, bind:
cms.aiseocode.com
In Railway:
Settings
→ Networking
→ Custom Domain
Add:
cms.aiseocode.com
Then go to your DNS provider and add the CNAME or TXT records Railway provides.
After DNS verification, your Strapi CMS will be available at:
https://cms.aiseocode.com/admin
Common Errors and Fixes
Error: Could not read package.json
This means you are not inside the Strapi project directory.
Fix:
cd /Users/your-name/aiseocode-cms
npm run develop
Error: Unsupported Node.js version
If Strapi says Node.js is not supported, switch to Node.js 22:
nvm install 22
nvm use 22
Error: App keys are required
This means APP_KEYS is missing in Railway.
Fix by adding:
APP_KEYS=key1,key2,key3,key4
Error: Application failed to respond
Check:
Railway Deployments → Logs
Common causes include:
Missing environment variables
Database connection error
Service not redeployed after variable changes
Wrong port
Final Result
After completing all steps, you will have:
A local Strapi development environment
A GitHub repository
A Railway Strapi production deployment
A Railway PostgreSQL database
A working Strapi admin panel
An Article content type
English and Chinese locale support
A future CMS backend for a Next.js website
This setup is suitable for a technical blog, AI SEO website, AI code resource site, or multilingual content platform.