---
title: "Deploy Keystone"
description: "Headless CMS that builds a GraphQL API from a TypeScript schema"
category: "CMS"
url: https://railway.com/deploy/keystone
---

# Deploy Keystone

Headless CMS that builds a GraphQL API from a TypeScript schema

**[Deploy Keystone on Railway](https://railway.com/template/keystone)**

- **Creator:** A3A
- **Category:** CMS

## Template content

### Postgres https://devicons.railway.app/i/postgresql.svg

- **Image:** ghcr.io/railwayapp-templates/postgres-ssl:18

### Redis https://cdn.sanity.io/images/sy1jschh/production/0ce0bfdcfbdbf69662b1116671f97c2dd788b655-157x157.svg

- **Image:** redis:8.2
- **Start command:** `/bin/sh -c "rm -rf $RAILWAY_VOLUME_MOUNT_PATH/lost+found/ && exec docker-entrypoint.sh redis-server --requirepass $REDIS_PASSWORD --save 60 1 --dir $RAILWAY_VOLUME_MOUNT_PATH"`

### keystone https://raw.githubusercontent.com/keystonejs/keystone/main/docs/public/apple-touch-icon.png

- **Source:** https://github.com/gridalpha/keystone-railway
- **Public domain:** Yes

## Buckets

- **keystone-assets**

## Documentation

![Keystone logo](https://repository-images.githubusercontent.com/128193054/7b6bc180-d843-11eb-9ae2-7c187964b002)

# Deploy and Host Keystone on Railway

Keystone is an open-source headless CMS for Node.js, built by Thinkmill under the MIT licence. You describe your content model once in a TypeScript file, and Keystone generates the database tables, a complete GraphQL API and a React admin interface from it. Because the schema is code rather than a point-and-click builder, content types, validation, hooks and per-field access control live in your repository and go through code review like everything else. Teams reach for it when a project needs a real application backend behind the content.

Self-host Keystone on Railway with this template and the pieces a production install needs are already wired together. The Keystone service is built from a public GitHub repository and serves the admin interface and the GraphQL API on one domain. PostgreSQL stores content through Prisma. Redis holds sessions, so signing out revokes them immediately and the app can run more than one replica. A managed object storage bucket takes image and file uploads, read back through presigned URLs. Nothing touches the container filesystem, so redeploys never lose data.

![Keystone, Postgres and Redis services on Railway](https://res.cloudinary.com/rroe4rtk/image/upload/v1787798579/keystone-architecture.png)

## Getting Started with Keystone on Railway

Deploy the template, set `ADMIN_EMAIL` and `ADMIN_PASSWORD`, and wait for the build. There is no setup wizard and no open registration: the first administrator is created from those two variables while the app boots, before it accepts a request, so the deployment is never briefly claimable by a stranger. Open the public URL, sign in at `/signin`, and you land on a dashboard listing the starter schema's content types — Users, Posts and Tags.

Create a tag or two, then open **Posts → New post**. Give it a title and slug, set the status to Published, write a few paragraphs in the rich-text document field, and attach a hero image and a file — both upload straight to object storage. Save, then confirm the API from your terminal:

```
curl -s -X POST https://your-app.up.railway.app/api/graphql \
  -H 'content-type: application/json' \
  -d '{"query":"{ posts { title slug status heroImage { url } } }"}'
```

A published post comes back with a presigned image URL; a draft does not appear at all, because anonymous callers are filtered to published content. That one request confirms the database, the API and object storage are healthy. Then edit `schema.ts` in your fork to model your own content.

![Keystone Posts list showing a published and a draft post](https://res.cloudinary.com/rroe4rtk/image/upload/v1787798581/keystone-posts-list.png)
![Keystone post editor with the rich-text document field](https://res.cloudinary.com/rroe4rtk/image/upload/v1787798583/keystone-post-editor.png)
![Post hero image, attachment, author and tags in Keystone](https://res.cloudinary.com/rroe4rtk/image/upload/v1787798584/keystone-assets-and-tags.png)

## About Hosting Keystone

Keystone is a framework rather than a prebuilt server, so a deployment is always your own application. This template is that application: a small but complete CMS you fork and extend. Its schema defines `Post` (title, slug, status, publish date, summary, rich text, hero image, attachment, author, tags), `Tag` and `User`, with access rules deciding who reads and writes.

Key features:

- **Schema-driven** — one file produces the database schema, the GraphQL API, TypeScript types and the admin interface.
- **Rich-text document field** — structured JSON, not HTML, so content renders cleanly everywhere.
- **Granular access control** — rules at operation, filter, item and field level, plain functions with the session in scope.
- **Images and files** — pluggable storage adapters; both go to S3-compatible storage here.
- **Prisma under the hood** — PostgreSQL, MySQL or SQLite, with migration files you commit.

Four services make up the deployment. **Keystone** runs the Node.js server answering the admin interface and `/api/graphql`. **PostgreSQL** stores every record. **Redis** stores sessions, so a sign-out genuinely invalidates one. The **object storage bucket** holds uploads, keeping the app stateless and horizontally scalable.

## Why Deploy Keystone on Railway

Railway removes the plumbing around a Node.js CMS:

- PostgreSQL, Redis and object storage provisioned and wired up for you
- Migrations applied on every deploy, before the new container serves traffic
- HTTPS domain, certificates and private networking handled
- Push to GitHub to rebuild and redeploy schema changes
- Scale vertically or horizontally without touching infrastructure

## Common Use Cases

- **Marketing sites and blogs** with a Next.js, Astro or Remix frontend on the GraphQL API.
- **Product catalogues and directories** where record relationships matter more than layout.
- **Internal tools and multi-channel content** — the admin interface doubles as a back office, and structured JSON feeds web, mobile and email clients alike.

## Dependencies for Keystone

- **Keystone** — built from [gridalpha/keystone-railway](https://github.com/gridalpha/keystone-railway): `@keystone-6/core`, `@keystone-6/auth`, `@keystone-6/fields-document`, Node 24.
- **PostgreSQL** — Railway's managed `postgres-ssl:18`, the content database.
- **Redis** — Railway's managed `redis:8.2`, the session store.
- **Object storage** — Railway managed bucket for image and file fields.

### Environment Variables Reference

| Variable | Purpose |
|---|---|
| `DATABASE_URL` | PostgreSQL connection string |
| `REDIS_URL` | Redis connection string for stored sessions |
| `SESSION_SECRET` | Signs session cookies; 32+ characters |
| `ADMIN_EMAIL` | First administrator's email address |
| `ADMIN_PASSWORD` | Their password; change it after first sign-in |
| `S3_*` | Bucket name, endpoint, region and credentials for uploads |
| `SESSION_MAX_AGE` | Session lifetime in seconds, default 30 days |
| `MAX_FILE_SIZE_BYTES` | Upload ceiling, default 50 MB |
| `GRAPHQL_PLAYGROUND` | `true` exposes Apollo's landing page |

### Deployment Dependencies

- Source repository: 
- Upstream: 
- Docs: 

## Hardware Requirements for Self-Hosting Keystone

| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 1 vCPU | 2 vCPU |
| RAM | 1 GB | 2 GB |
| Storage | Database only | 10 GB + object storage |
| Runtime | Node.js 20+ | Node.js 24 |

An idle Keystone service sits at roughly 130 MB of memory, rising to about 420 MB while it boots and applies migrations.

## Self-Hosting Keystone

To run this locally, clone the repository, install dependencies and point it at a PostgreSQL database:

```
git clone https://github.com/gridalpha/keystone-railway
cd keystone-railway
npm install
export DATABASE_URL=postgresql://postgres:postgres@localhost:5432/keystone
export SESSION_SECRET=$(openssl rand -base64 32)
npx keystone dev
```

`keystone dev` pushes the schema to your database and serves the admin interface on . For production, generate artifacts, apply committed migrations and start the server:

```
npx keystone build
npx prisma migrate deploy
npx keystone start
```

To start from scratch instead of forking, run `npm create keystone-app@latest`. Either way, after editing `schema.ts` run `npx keystone build --no-ui`, then `npx prisma migrate dev`, and commit the migration.

## How Much Does Keystone Cost to Self-Host?

Keystone is free and open source under the MIT licence: no paid tier, seat limits or feature gates, no vendor account and no usage metering. Your only cost on Railway is infrastructure — the Keystone service, PostgreSQL, Redis, and the storage your uploads occupy.

## Keystone vs Strapi and Payload

| | Keystone | Strapi | Payload |
|---|---|---|---|
| Schema | TypeScript code | Admin UI builder | TypeScript code |
| Primary API | GraphQL | REST + GraphQL | REST + GraphQL |
| Licence | MIT | MIT, paid tiers | MIT, paid tiers |

Strapi suits teams wanting non-developers to shape content types in a browser, and Payload leans hard on Next.js. Keystone fits teams who want the schema in code, GraphQL first, and no paid tier between them and the full feature set.

## FAQ

**What is Keystone?**
An open-source headless CMS and application framework for Node.js. You define your content model in TypeScript and it generates a database schema, a GraphQL API and a React admin interface from that definition.

**What does this Railway template deploy?**
A Keystone application built from a public GitHub repository, a managed PostgreSQL database, a Redis instance for sessions, and an object storage bucket for uploads. Admin interface and GraphQL API share one domain.

**Why does the template include Redis and an object storage bucket?**
PostgreSQL stores content; Redis stores sessions, so the cookie is only an opaque identifier, signing out deletes the session server-side, and several replicas are safe. Container filesystems are replaced on every deploy, so uploads stream to the bucket and are served through presigned URLs.

**How do I change the content schema after deploying?**
Fork the repository, edit `schema.ts`, run `npx keystone build --no-ui` and `npx prisma migrate dev` against a development database, then commit the migration. Pushing rebuilds the service and applies it before the new container takes traffic.

**Can anonymous visitors read my content through the GraphQL API?**
Only published posts and tags. Drafts, the user list and every write need a signed-in session, and the admin interface is closed to anonymous visitors. Adjust these rules in `schema.ts`.


## Similar templates

- [Libredesk - Complete Setup](https://railway.com/deploy/libredesk-complete-setup) — Complete self-hosted omnichannel customer support desk.
- [Paperless-ngx](https://railway.com/deploy/paperless-ngx-3) — Paperless-ngx — document management with OCR and full-text search
- [Instatic CMS - Postgres](https://railway.com/deploy/instatic-cms-postgres) — Design, build and manage powerful static sites from state-of-the-art CMS

Open this page in a browser: https://railway.com/deploy/keystone
