Deploy Strapi
Content management system with an editor and an API for any site
Just deployed
/var/lib/postgresql/data
strapi
Just deployed
strapi-media
Bucket
Just deployed

Deploy and Host Strapi on Railway
Strapi is an open-source headless CMS built on Node.js. You model content as structured types — articles, products, landing pages — and Strapi gives editors a polished admin panel plus an automatically generated REST and GraphQL API to read them from any front end. Teams reach for it when a traditional CMS forces its templating on them but a bare database is too little. It powers Next.js marketing sites, mobile back ends, e-commerce catalogues and documentation portals.
Self-host Strapi on Railway and the template wires the pieces together. The strapi service builds from the gridalpha/strapi-railway repository, whose Dockerfile compiles the admin panel at build time, so containers start in seconds. A managed Postgres service stores content, users and permissions, and a Railway object storage bucket holds media uploads, so the container keeps no durable state. Postgres and the bucket stay private.

Getting Started with Strapi on Railway
Once the deploy goes green, open the public URL and add /admin. Strapi ships no default credentials — the first visit shows a registration form creating the super administrator, and it stays open until somebody claims it, so register immediately after deploying. The password needs at least eight characters with an uppercase letter, a lowercase letter and a number.
You land on the dashboard. Click Content Manager and you will find an example Article type with title, slug, excerpt, rich-text body and cover image. Create an entry, press the refresh icon beside the slug to generate one, then hit Publish. Open Media Library and upload an image — if the thumbnail renders, your bucket and credentials are correct, because it is served straight from object storage.
To confirm the API, go to Settings → Users & Permissions → Roles → Public, tick find and findOne for Article and save. Fetching /api/articles?populate=cover now returns the entry as JSON with its cover — one request proving database, API and storage are all wired.

About Hosting Strapi
Strapi separates content management from delivery. Editors work in the admin panel; your front end consumes JSON. Nothing about presentation is baked in, so the same content can drive a website, an iOS app and a digital sign at once. Self-hosting keeps the database, the media and the API in infrastructure you control, with no per-seat pricing.
Key capabilities:
- Content-Type Builder — collection and single types with relations, components and dynamic zones
- Auto-generated REST and GraphQL APIs with filtering, sorting, pagination and deep population
- Draft and publish plus internationalisation for multi-locale content
- Role-based access control for admins and API consumers, with scoped tokens
- Media library with responsive image variants on upload
- Plugin system and lifecycle hooks for custom logic
The strapi container runs the admin panel and API. Postgres is the system of record — every entry, user, role and API token lives there, which is why the template provisions it instead of SQLite on ephemeral disk. The object storage bucket holds uploads, so a redeploy replaces the container without losing an image.
Why Deploy Strapi on Railway
- Postgres provisioned and connected by reference — no connection strings to copy
- Object storage attached, so uploads survive every redeploy
- Builds straight from the source repository on every push
- TLS, public domain and private networking configured automatically
- Health checks and restart policies already set
Common Use Cases
- Marketing sites and blogs — editors publish in Strapi while Next.js, Nuxt or Astro renders statically
- Mobile and web app back ends — one content API serving iOS, Android and web from a single model
- E-commerce catalogues — products, variants, categories and imagery consumed by a storefront
- Multi-locale content hubs — locale variants with role-scoped teams
Dependencies for Strapi
- Strapi 5 (
@strapi/strapi), built from gridalpha/strapi-railway — application and admin panel - PostgreSQL 18 (
ghcr.io/railwayapp-templates/postgres-ssl:18) — all content, users and permissions - Railway object storage bucket — media uploads and their generated image variants
Environment Variables Reference
| Variable | Purpose |
|---|---|
APP_KEYS | Comma-separated session signing keys |
ADMIN_JWT_SECRET, JWT_SECRET | Sign admin sessions and API tokens |
API_TOKEN_SALT, TRANSFER_TOKEN_SALT | Salt generated tokens |
ENCRYPTION_KEY | Encrypts sensitive values at rest |
DATABASE_URL | Postgres connection string |
AWS_BUCKET, AWS_ENDPOINT, AWS_REGION | Object storage location |
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY | Object storage credentials |
AWS_SIGNED_URL_EXPIRES | Media link lifetime in seconds |
PUBLIC_URL | Override canonical URL for a custom domain |
The six secrets are generated at deploy time. Do not rotate them on a running instance — changing ENCRYPTION_KEY makes encrypted values unreadable, and changing the JWT secrets invalidates every admin session and API token.
Deployment Dependencies
- Strapi docs · Strapi on GitHub
- Source repository
- Node.js 22 runtime, PostgreSQL 18
Hardware Requirements for Self-Hosting Strapi
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 1 vCPU | 2 vCPU |
| RAM | 1 GB | 2 GB |
| Storage | Database only (media on object storage) | 10 GB Postgres volume |
| Runtime | Node.js 22, PostgreSQL 14+ | Node.js 22, PostgreSQL 18 |
Self-Hosting Strapi
Content types in Strapi are code, not database rows. The Content-Type Builder is disabled when NODE_ENV=production, because adding a type writes files and needs a restart. Model locally and ship through git — clone the repository and run it against SQLite:
git clone https://github.com/gridalpha/strapi-railway
cd strapi-railway
npm install
cp .env.example .env
npm run develop
That opens the admin on http://localhost:1337/admin with the Content-Type Builder available. Build your types, commit the generated files and push — Railway rebuilds and they appear in the Content Manager:
git add src/api
git commit -m "add content types"
git push
To run the production image locally, build the repository's Dockerfile and pass the same variables the template sets — DATABASE_CLIENT, DATABASE_URL, APP_KEYS and the five remaining secrets.
Is Strapi Free to Self-Host?
Strapi's Community Edition is free and open source, with no cap on content types, entries, API calls or admin users. Paid tiers add single sign-on, audit logs and release management — none of which a production site requires. Self-hosting on Railway costs infrastructure only: the container, Postgres and your media storage, typically a few dollars a month for a small site.
FAQ
What is Strapi? An open-source headless CMS on Node.js. It gives editors an admin panel for structured content and developers an automatically generated REST and GraphQL API, leaving the front end to you.
What does this Railway template deploy? The Strapi 5 app built from a production Dockerfile, a managed PostgreSQL 18 database, and an object storage bucket for media. Secrets are generated at deploy time and services connected by reference.
Why does the template include Postgres instead of SQLite? SQLite would live on the container filesystem, replaced on every deploy, so content would disappear. Postgres is what Strapi recommends for production and makes concurrent editing safe.
Where do uploaded images go, and why do their URLs contain a signature?
Media goes to the object storage bucket, not container disk, so it survives redeploys. The bucket is private, so Strapi serves each file through a time-limited signed URL — including to anonymous readers of the public API. Links last seven days; adjust AWS_SIGNED_URL_EXPIRES if your build caches them longer.
How do I create content types on a deployed instance?
Not in production — the Content-Type Builder is disabled when NODE_ENV=production because it writes files and needs a restart. Clone the repository, run npm run develop, model your types, then commit src/api and push. Railway rebuilds and they appear.
How do I connect a Next.js or Nuxt front end?
Enable find and findOne under Settings → Users & Permissions → Roles → Public, or create a scoped token under Settings → API Tokens and send it as a bearer token. Then fetch /api/?populate=*.
Can I run more than one instance of Strapi?
The template ships one replica. Media lives in object storage and state in Postgres, so the app is stateless — but Strapi runs scheduled jobs in-process without leader election, so anything in config/cron.js runs once per replica. Handle that before scaling out.
Template Content
strapi
gridalpha/strapi-railwaystrapi-media
Bucket