---
title: "Deploy Deploy Postgres HA with pg_cron"
description: "Scheduled SQL jobs on a highly available Patroni cluster"
category: "Storage"
url: https://railway.com/deploy/deploy-postgres-ha-with-pgcron
---

# Deploy Deploy Postgres HA with pg_cron

Scheduled SQL jobs on a highly available Patroni cluster

**[Deploy Deploy Postgres HA with pg_cron on Railway](https://railway.com/template/deploy-postgres-ha-with-pgcron)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/deploy-postgres-ha-with-pgcron/manifest.json

- **Creator:** onepush
- **Category:** Storage

## Template content

### pg-3

- **Image:** ghcr.io/onepush-dev/postgres-ha-node:18.6@sha256:31e91770e734468e2da836067da77c2d5505425c4e96779fee07c79f69f2f585

### pg-2

- **Image:** ghcr.io/onepush-dev/postgres-ha-node:18.6@sha256:31e91770e734468e2da836067da77c2d5505425c4e96779fee07c79f69f2f585

### pg-1

- **Image:** ghcr.io/onepush-dev/postgres-ha-node:18.6@sha256:31e91770e734468e2da836067da77c2d5505425c4e96779fee07c79f69f2f585

### Postgres

- **Image:** ghcr.io/onepush-dev/postgres-ha-router:18.6@sha256:7a01696b8161be78693b957469d63976a796c8d1e721f0c9aca48736743bce98
- **Health check:** /health

## Documentation

# Deploy and Host self hosted Postgres HA pg_cron (Scheduled Jobs for High-Availability Postgres) on Railway

This template runs a three-node Patroni and etcd Postgres 18.6 cluster with pg_cron preloaded. Jobs run only on the primary and survive failover.

## About Hosting Postgres HA pg_cron open-source software on Railway (self hosted pg_cron scheduling on a Patroni Postgres HA cluster template)

You own the data and the cron jobs both.

## Why Deploy Postgres HA pg_cron, the Amazon RDS alternative on Railway (Railway Free Trial)

Amazon RDS supports pg_cron, but you pay for the managed control plane and get less say over how the cluster is laid out.

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 Postgres HA pg_cron 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.

### Railway vs Other Hosting Providers and VPS for Postgres HA pg_cron self hosting

Railway ships the three Patroni nodes and the HAProxy router pre-wired, while the options below leave that layer to you.

| Provider | What You Get with Railway | What You Get with the Other Provider |
| --- | --- | --- |
| DigitalOcean | Three nodes and a router from one template, with pg_cron preloaded. | Droplets, but you write the Patroni and etcd config yourself. |
| AWS | RW 5432 and RO 5433 ports with no VPC setup before cron.schedule. | Fine-grained control over instances and storage, with setup first. |
| Hetzner | Postgres 18.6 images already pinned, so no OS hardening or bootstrap. | Cheap servers where you run the etcd quorum and failover tests. |

On a VPS you own failover end to end, which helps if you need custom Patroni tuning.

## Common Use Cases for hosted Postgres HA pg_cron

- **Nightly cleanup of expired rows:** Schedule a cron.schedule job that deletes expired sessions at 03:00 so the table stays small. It runs on whichever node is primary, so it keeps working after a Patroni failover.
- **Periodic materialized view refreshes:** Refresh a reporting view every 15 minutes with REFRESH MATERIALIZED VIEW CONCURRENTLY. If a run is still going, pg_cron queues the next one instead of starting a parallel copy.
- **Scheduled VACUUM or ANALYZE:** Target a high-churn table in a quiet window, then check cron.job_run_details to confirm the job finished.
- **Pruning cron.job_run_details:** pg_cron never cleans its own log, so add a weekly job that deletes run records older than seven days.
- **Per-database maintenance:** pg_cron lives in one database only, so use cron.schedule_in_database to run cleanup in a second application database from the same scheduler.

## Dependencies for Postgres HA pg_cron Docker hosted on Railway

This template runs as a Patroni and etcd cluster, so the database side is three Postgres nodes plus a router.

### Deployment Dependencies for Managed Postgres HA pg_cron Service (Database)

- **pg-1, pg-2, pg-3:** Patroni plus etcd on Postgres 18.6, image ghcr.io/onepush-dev/postgres-ha-node:18.6, with pg_cron included.
- **Postgres router:** HAProxy from ghcr.io/onepush-dev/postgres-ha-router:18.6, exposing RW port 5432, RO port 5433 and health HTTP on 8080.
- **Volumes:** each node needs its own persistent volume for the data directory, or your jobs and run history will not survive a restart.

### Implementation Details for Postgres HA pg_cron (Using Postgres HA official docker image)

Set PATRONI_SCOPE to the same value on all three nodes (pg-ha by default) so they form one cluster. Point cron.schedule calls at DATABASE_URL, which reaches the primary on 5432.

## How does Postgres HA pg_cron compare against other ways to run scheduled SQL jobs on managed and self-hosted Postgres

### Postgres HA pg_cron vs Amazon RDS (Amazon RDS Alternative)

- **Where RDS wins:** AWS handles patching, backups, and node replacement, so you never touch Patroni or etcd.
- **Where this template wins:** You get pg_cron on a three-node Patroni cluster you control, and jobs run on the primary and move with it during failover.
- **Setup difference:** Add pg_cron to shared_preload_libraries and restart before CREATE EXTENSION pg_cron will work.

### Postgres HA pg_cron vs Supabase (Supabase Alternative)

- **Where Supabase wins:** You get a dashboard, auth, and auto-generated APIs on top of Postgres, which is a faster start for a full backend.
- **Where this template wins:** It's a plain Postgres cluster. You write cron.schedule calls directly and inspect cron.job_run_details yourself.
- **Scope:** If you only need scheduled SQL, this template is narrower on purpose, and you own the cleanup jobs and log retention.

### Postgres HA pg_cron vs Crunchy Bridge (Crunchy Bridge Alternative)

- **Where Crunchy Bridge wins:** It's a managed PostgreSQL service where the operations work is handled for you.
- **Where this template wins:** You run Patroni and etcd with a known topology: pg-1, pg-2, and pg-3 behind the HAProxy router on RW 5432 and RO 5433.
- **Connection detail:** Schedule through DATABASE_URL, since DATABASE_URL_READONLY on 5433 points at replicas and will reject cron.schedule writes.

### Postgres HA pg_cron vs Neon (Neon Alternative)

- **Where Neon wins:** It's serverless Postgres with branching, which suits dev and preview environments that can scale to zero.
- **Where this template wins:** It's a steady, always-on cluster, so recurring jobs fire on schedule without waking compute on demand.
- **Cost shape:** Neon bills by compute time, while this template's cost is the fixed footprint of three nodes plus the router, which is easier to predict for nightly maintenance.

## How to use Postgres HA pg_cron (the OSS database cluster)?

Do these steps on day one, after the template deploys. Then create the extension, schedule a test job, and confirm it ran.

1. Add pg_cron to shared_preload_libraries in postgresql.conf and restart PostgreSQL.
2. Connect through DATABASE_URL, the router primary on RW port 5432. Skip DATABASE_URL_READONLY on 5433, because replicas reject cron.schedule writes.
3. As a superuser, create the extension in the database named by cron.database_name.
4. Schedule a test job and check the run history after it fires.
5. Add a cleanup job so the run log doesn't grow forever.

```sql
ALTER SYSTEM SET shared_preload_libraries = 'pg_cron';
-- restart PostgreSQL, then:
CREATE EXTENSION pg_cron;
SELECT cron.schedule('job_name', '*/5 * * * *', 'command');
SELECT * FROM cron.job_run_details ORDER BY start_time DESC LIMIT 5;
SELECT cron.schedule('prune_cron_log', '0 3 * * *',
  $$DELETE FROM cron.job_run_details WHERE end_time &lt; now() - interval '7 days'$$);
```

## How to self host Postgres HA pg_cron on other VPS Services (Postgres HA self hosting guide)

### Clone the Repository

Clone the template repository onto the VPS and check out the Postgres 18.6 build.

```bash
git clone https://github.com/your-org/postgres-ha-pg-cron.git
cd postgres-ha-pg-cron
```

### Install Dependencies

Install Docker Engine and the Compose plugin, then confirm the daemon is running.

```bash
sudo apt-get install -y docker.io docker-compose-plugin
sudo systemctl enable --now docker
```

### Configure Environment Variables

Copy the example env file and set the superuser, replication, and REST API passwords to long random values.

```bash
cp .env.example .env
# set PATRONI_SUPERUSER_PASSWORD, PATRONI_REPLICATION_PASSWORD, PATRONI_RESTAPI_PASSWORD
# set PGHA_NODES=pg-1-host,pg-2-host,pg-3-host
```

### Start the Postgres HA pg_cron Application

Bring the cluster up and confirm a leader has been elected.

```bash
docker compose up -d
curl -s http://your-domain:8008/cluster
```

Railway handles node placement, private networking, and router wiring for you, which is the part that takes real effort on a plain VPS.

## Official Pricing of Postgres HA pg_cron (Postgres HA pricing)

Postgres HA pg_cron is free and open source, so there is no license fee to pay. You pay only for the infrastructure it runs on.

## Postgres HA pg_cron cloud vs self hosted comparison (Pricing, features, costs, and more)

Self hosting pg_cron on this template means you pay for compute and storage on Railway instead of a managed vendor's bundle. The extension behaves the same either way.

### Monthly cost of self hosting Postgres HA pg_cron on Railway

Railway's rough range for this template is about $25-60 per month for three Postgres nodes plus the router at light use, and it rises as data and RAM grow.

### System Requirements for Hosting Postgres HA pg_cron on a VPS

Plan for three nodes so Patroni keeps quorum through a failure, with etcd on each node. Size disks for your data and the run history you keep.

## Frequently Asked Questions (FAQs)

### Does pg_cron run on the replicas or only the primary?

Only the primary. pg_cron does not run jobs in hot standby, so the schedule fires on whichever node Patroni holds as primary.

### Does a scheduled job survive a Patroni failover?

Yes. A run in progress during the failover will show as failed in cron.job_run_details.

### Why does CREATE EXTENSION fail until the server is restarted?

pg_cron must be loaded at server start, so set shared_preload_libraries = 'pg_cron' in postgresql.conf and restart PostgreSQL first.

### How do I schedule a job into a different database?

Use cron.schedule_in_database(job_name, schedule, command, database, username, active) from the cron database. pg_cron lives in only one database per cluster, so this is how you point a job at another one.

### Why are my job runs missing from cron.job_run_details?

Check that cron.log_run is not set to off, since that disables logging entirely.

### What timezone do cron schedules use?

The default is GMT.


## Similar templates

- [RustFS | (Just Updated) S3 Object Store, Public URL and Keys Set](https://railway.com/deploy/rustfs-or-just-updated-s3-object-store-p) — S3-compatible object store, keys and public URL preset, volume kept
- [TimescaleDB](https://railway.com/deploy/timescaledb-railway-template) — A PostgreSQL-based time-series database for analytics on Railway.
- [Garage S3 Storage](https://railway.com/deploy/garage-s3-storage) — Ultra-light S3 server: fast, open-source, plug-and-play.

Open this page in a browser: https://railway.com/deploy/deploy-postgres-ha-with-pgcron
