---
title: "Deploy Postgres S3 Backups with Cleanup"
description: "PostgreSQL backups, configurable cleanup and S3 storage with tracing"
category: "Automation"
url: https://railway.com/deploy/postgres-s3-backups-with-cleanup
---

# Deploy Postgres S3 Backups with Cleanup

PostgreSQL backups, configurable cleanup and S3 storage with tracing

**[Deploy Postgres S3 Backups with Cleanup on Railway](https://railway.com/template/postgres-s3-backups-with-cleanup)**

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

- **Creator:** justMax
- **Category:** Automation

## Template content

### Backup Cleanup

- **Source:** maxstue/postgres-s3-backups-cleanup
- **Start command:** `/usr/local/bin/cleanup`

### Backup CRON

- **Source:** maxstue/postgres-s3-backups-cleanup

## Buckets

- **Bucket**

## Documentation

# Deploy and Host Postgres S3 Backups with Cleanup on Railway

Back up an existing PostgreSQL database to S3-compatible storage and manage retention with two independent Go applications. This template includes a streaming backup service, a cleanup service, and a dedicated Railway bucket. Backup operations include OpenTelemetry tracing.

## About Hosting Postgres S3 Backups with Cleanup

Three resources are included:
- **Backup CRON**: streams a PostgreSQL dump through parallel gzip compression directly to concurrent S3 multipart uploads.
- **Backup Cleanup**: previews or deletes expired backups while preserving a configurable minimum number.
- **Bucket**: dedicated S3-compatible storage connected to both applications through generated reference variables.

Both applications live in one Go module but build independently. Each has its own entrypoint, binary, Dockerfile, runtime configuration and cron schedule. Their Dockerfiles copy only the corresponding application's source.

Deploy into the Railway project containing your existing PostgreSQL service and provide `BACKUP_DATABASE_URL`, for example `${{Postgres.DATABASE_URL}}`. No database is created by the template. External databases must be reachable from the backup service.

## Common Use Cases

- Scheduled logical PostgreSQL backups to object storage.
- Configurable age-based retention with minimum backup preservation.
- Backup tracing and dry-run cleanup previews.

## Dependencies for Postgres S3 Backups with Cleanup Hosting

- An existing PostgreSQL database and connection URL.
- The included Railway bucket, or external S3-compatible storage configured on both services.
- [Source repository](https://github.com/maxstue/postgres-s3-backups-cleanup).

### Independent builds

Both services build from repository root `/`:
- Backup uses `RAILWAY_DOCKERFILE_PATH=docker/backup.Dockerfile`.
- Cleanup uses `RAILWAY_DOCKERFILE_PATH=docker/cleanup.Dockerfile`.

Both run once and exit. Native Railway Cron controls when each starts. Neither service needs the other application running.

> **Important: cleanup does not delete backups by default.**
> `DRY_RUN=true` only logs which backups would be deleted. To enable actual deletion, open **Backup Cleanup → Variables**, set **`DRY_RUN=false`**, and apply/deploy the change. Subsequent runs can then delete eligible backups, including any run started by deployment. The cron schedule remains unchanged.

### Configuration

All defaults can be changed. Cron schedules use UTC and are edited under each service's **Settings → Cron Schedule**.

| Setting | Default |
| --- | --- |
| Backup schedule | `0 2 1 * *`: monthly, day 1 at 02:00 UTC |
| Cleanup schedule | `0 3 1 1,7 *`: January/July, day 1 at 03:00 UTC |
| `RETENTION_DAYS` | `183` days |
| `KEEP_MIN` | Preserve at least `1` newest backup |
| `DRY_RUN` | `true`: preview only |
| `PG_VERSION` | `18`; must be at least your PostgreSQL server major version |
| `RUN_ON_STARTUP` | `true`: run the backup once and exit |
| `GZIP_CONCURRENCY` | `20` compression workers |
| `UPLOAD_CONCURRENCY` | `20` upload workers |

More compression/upload workers can improve throughput but increase memory use. Blocks and upload parts are each 5 MiB.

Edit retention values under **Backup Cleanup → Variables**. Review its logs, then set `DRY_RUN=false` to enable deletion. Cleanup inventories every page before deleting and preserves the newest `KEEP_MIN` objects, even when expired. A listing failure stops the run before any deletion. Keep the bucket dedicated to backups.

For external S3, configure endpoint, bucket, region and credentials on both services.

### Tracing and validation

Enable Railway tracing on **Backup CRON** after deployment. The Go SDK reads platform-provided OTLP variables and service identity, emits `backup.run`, PostgreSQL `pg_dump` CLIENT spans and S3 operation spans, and flushes before exit. Credentials, connection URLs, bucket names and object keys are excluded from span attributes/events. Leave automatic instrumentation off. Cleanup writes structured Railway logs.

The repository includes tests for streaming integrity, multipart failures, cancellation, bounded buffering, tracing, retention boundaries, pagination, dry-run and configuration validation. All checks run from the repository root.

Regularly test restoring backups. Logical backups do not provide continuous point-in-time recovery. Storage accumulates until deletion is enabled and a cleanup run occurs.

## Why Deploy Postgres S3 Backups with Cleanup on Railway?

Railway schedules both independent applications and provisions their storage. Generated reference variables connect the services to the backup bucket without storing credentials in source control.

Thanks to [Brody](https://github.com/brody192/pg_backup) and the [original Railway template](https://github.com/railwayapp-templates/postgres-s3-backups) for the foundation of this project.


## Similar templates

- [N8N Main + Worker](https://railway.com/deploy/n8n-main-worker) — Deploy and Host N8N with Inactive worker.
- [Evolution API with n8n](https://railway.com/deploy/evolution-api-with-n8n) — Automate WhatsApp workflows with Evolution API, n8n, and Postgres.
- [Postgres Backup](https://railway.com/deploy/postgres-s3-backups) — Cron-based PostgreSQL backup to bucket storage

Open this page in a browser: https://railway.com/deploy/postgres-s3-backups-with-cleanup
