---
title: "Deploy PostgREST | (Just Updated) REST API for Postgres, JWT Secret Generated, Data Survives Redeploys"
description: "REST API for Postgres with JWT auth. Secrets generated, data persists."
category: "Other"
url: https://railway.com/deploy/postgrest-or-just-updated-rest-api-for-p
---

# Deploy PostgREST | (Just Updated) REST API for Postgres, JWT Secret Generated, Data Survives Redeploys

REST API for Postgres with JWT auth. Secrets generated, data persists.

**[Deploy PostgREST | (Just Updated) REST API for Postgres, JWT Secret Generated, Data Survives Redeploys on Railway](https://railway.com/template/postgrest-or-just-updated-rest-api-for-p)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/postgrest-or-just-updated-rest-api-for-p/manifest.json

- **Creator:** SuperSlowSloth
- **Category:** Other

## Template content

### postgrest

- **Image:** ghcr.io/bon5co/postgrest-railway@sha256:730411893fa046656d656ca8e3300bbe45948b2f96ed5ac116089105162f3507
- **Health check:** /
- **Public domain:** Yes

### postgres

- **Image:** postgres:18.6@sha256:74935e72241653ca55e0414067e6d8763aceb8a810eb51b452253ec3dcfc4336
- **Start command:** `/bin/sh -c 'printf "CREATE ROLE anon NOLOGIN;\nCREATE ROLE authenticated NOLOGIN;\nGRANT anon, authenticated TO postgres;\nCREATE TABLE IF NOT EXISTS public.todos (id serial PRIMARY KEY, task text NOT NULL, done boolean NOT NULL DEFAULT false);\nINSERT INTO public.todos (task) SELECT chr(104)||chr(101)||chr(108)||chr(108)||chr(111);\nGRANT USAGE ON SCHEMA public TO anon, authenticated;\nGRANT SELECT ON public.todos TO anon;\nGRANT ALL ON public.todos TO authenticated;\nGRANT USAGE, SELECT ON SEQUENCE public.todos_id_seq TO authenticated;\n" > /docker-entrypoint-initdb.d/00-postgrest.sql; exec docker-entrypoint.sh postgres'`

## Documentation

# Deploy and Host PostgREST on Railway

PostgREST turns a PostgreSQL database into a RESTful API straight from its schema, with JWT authentication and role-based access. This template deploys it together with its own Postgres database, with the JWT secret and database password generated for you.

## About Hosting PostgREST

The template starts two services: `postgrest` (the API server, public HTTPS domain) and `postgres` (private, on a persistent volume). PostgREST connects to Postgres over Railway's private network. A demo `public.todos` table, an `anon` role (read only) and an `authenticated` role (full access) are created on first boot, so the API answers something useful immediately. `PGRST_JWT_SECRET` is generated per deploy; sign a JWT with it and a `role` claim to write.

Machine-readable contract:

```
public_url:     https://${RAILWAY_PUBLIC_DOMAIN of service postgrest}
internal_url:   http://postgrest.railway.internal:8080
openapi:        GET /  (OpenAPI document, 200 when ready)
tables:         GET/POST/PATCH/DELETE /
health:         GET /  (200 when ready)
credentials:    PGRST_JWT_SECRET (service postgrest, HS256), POSTGRES_PASSWORD (service postgres)
database_url:   PGRST_DB_URI (service postgrest)
roles:          anon (read), authenticated (read/write) - JWT claim "role"
port:           8080 (HTTP)
```

Working checks, run them after the deploy turns green:

```
curl -s https:///todos
# [{"id":1,"task":"hello","done":false}]

# write: sign an HS256 JWT with PGRST_JWT_SECRET and payload {"role":"authenticated"}
curl -s -X POST https:///todos \
  -H "Authorization: Bearer $JWT" -H 'content-type: application/json' \
  -H 'Prefer: return=representation' -d '{"task":"agent-write"}'
# [{"id":2,"task":"agent-write","done":false}]
```

An anonymous write is rejected with 401 `permission denied`. Data lives on a volume mounted at `/var/lib/postgresql`, so it survives redeploys.

## Why Deploy PostgREST on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying PostgREST on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.

- REST API and Postgres in one click
- JWT secret and database password generated automatically
- Data kept on a persistent volume
- Images pinned by digest, so redeploys do not change versions

## Common Use Cases

- Instant REST API over a new or existing Postgres schema
- Backend for web and mobile apps with row-level security
- Data API for AI agents that need an authenticated HTTP surface
- Replacing hand-written CRUD services

## Dependencies for PostgREST Hosting

### Deployment Dependencies

- [PostgREST on GitHub](https://github.com/PostgREST/postgrest)
- [PostgREST documentation](https://docs.postgrest.org/)
- [PostgREST Docker image](https://hub.docker.com/r/postgrest/postgrest)
- [PostgreSQL](https://www.postgresql.org/)

### Implementation Details

The service runs a thin wrapper image (`ghcr.io/bon5co/postgrest-railway`) over the official `postgrest/postgrest` image, pinned by digest; it only sets environment defaults and binds port 8080. Rotate the JWT secret by editing `PGRST_JWT_SECRET` on the `postgrest` service and redeploying.
<table></table>

## Similar templates

- [Rocky Linux](https://railway.com/deploy/rocky-linux) — Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀
- [Foundry Virtual Tabletop](https://railway.com/deploy/X5tR6G) — A Self-Hosted & Modern Roleplaying Platform
- [Letta Code Remote](https://railway.com/deploy/letta-code-remote) — Run a Letta Code agent 24/7. No inbound ports, just deploy.

Open this page in a browser: https://railway.com/deploy/postgrest-or-just-updated-rest-api-for-p
