Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

render-postgres-alternative

PostgreSQL backup shell License

If you are here because a countdown is running, skip to Do this first. It works whether you migrate or not.

Render's free PostgreSQL instances expire 30 days after creation. After expiry there is a grace period in which you can upgrade to a paid instance; once that ends, Render deletes the database and everything in it. Render also documents that free databases do not support any form of backup.

Those two facts together are the whole problem. Not "the free tier is restrictive" — free tiers are supposed to be restrictive — but that the restriction is a deletion date, and the product that would normally save you from a deletion date is the one thing the free tier does not include.

So the first thing in this repository is a backup script, not a migration guide. Take the backup. Decide afterwards — a free PostgreSQL 16.2 instance with no expiry countdown is one of the destinations further down, and it will still be there once the dump is on disk.

Contents

examples/
  render-backup.sh   dump + verify + rotate + count down to expiry
  restore-into.sh    restore anywhere, with a rollback snapshot of the target
  schedule.md        cron / systemd timer / GitHub Actions

Do this first (fifteen minutes)

git clone https://github.com/freebase-cloud/render-postgres-alternative
cd render-postgres-alternative/examples

# Render dashboard -> your instance -> Connect -> External
export DATABASE_URL='postgresql://user:pass@host.oregon-postgres.render.com/dbname'
export DB_CREATED_AT='2026-08-01'          # the day you created it
export BACKUP_DIR=./backups

./render-backup.sh

You now have a verified logical backup on a machine you control, and a script that tells you how many days are left. Put it on a schedule — examples/schedule.md has cron, a systemd timer and a GitHub Actions workflow, with the trade-offs of each spelled out.

What the script does beyond pg_dump:

  • Refuses to run twice at once (flock, or a directory lock without it).
  • Writes both a directory-format archive and a schema-only .sql you can diff.
  • Runs pg_restore --list over every dump before calling it a success. An unreadable dump is the failure that stays quiet until you need it.
  • Rotates to the newest KEEP backups and touches nothing it did not create.
  • Exits 3 when the instance is within seven days of expiry — separate from 0 (fine) and 1 (backup failed), so your scheduler can act on the difference.
  • POSTs to ALERT_WEBHOOK on failure or near-expiry, because cron mail goes nowhere on most containers.

Then test a restore into a throwaway container, or into a free Postgres instance if you would rather the rehearsal doubled as the destination. A backup you have never restored is a hypothesis, not a backup.


The clock, precisely

Event What happens
Day 0 Free instance created
Approaching day 30 Render emails a warning
Day 30 Instance expires; a grace period begins in which you can upgrade
Approaching end of grace Render emails again
End of grace Render deletes the database and its data
Throughout Free instances have no backups of any kind

Last verified: 2026-08-18 against Render's free tier docs and Render Postgres backups docs. Terms change; re-read them before you plan around a date.

Two smaller details that bite people. Free web services spin down after 15 minutes without traffic and lose local filesystem changes — if your app was writing anything to disk alongside the database, that is also not persistent. And the internal connection string only resolves inside Render's network, so a backup job running anywhere else must use the external URL.


Reasons to stay on Render

Not filler. Render is a good product and half the people reading this should upgrade rather than migrate.

  • The app and the database are one deploy. Render's integrated story — push a repo, get a service, attach a managed Postgres in the same network, with a Blueprint describing the whole thing in version control — is the reason to use Render at all. Moving the database off-platform breaks the private network hop, adds public-internet latency to every query, and leaves you operating two providers for one application. If you like Render, upgrade the database and stop reading.
  • Paid instances get real recovery. Point-in-time recovery over a rolling window, and dashboard-generated logical backups retained for a week. That is the specific thing the free tier is missing, and it is available for money.
  • Zero-downtime deploys, private networking, preview environments. None of these come back if you leave, and reproducing them elsewhere is not a weekend.
  • The database is genuinely the cheap part. Compare a paid instance against the hours a migration will take. For a project with revenue, the arithmetic is usually not close.
  • A 30-day expiry is honest. Render tells you the date up front. That is materially better than a free tier that quietly degrades, or one that disappears with a blog post and eight weeks' notice.

Migrate if this is a hobby project that will never justify a monthly line item, if you want a database that outlives whichever platform hosts the app, or if you are using Render Postgres as a scratch database for development and the 30-day cycle is simply annoying.


Where the backup can go

Target Fits Note
Paid Render Postgres Anyone happy on Render PITR and dashboard backups; keeps the private network hop
Self-hosted Postgres Full control You now own patching, backups and uptime
Another managed provider Production Read the free-tier terms before you rely on one
freebase.cloud Development, prototyping, small production workloads Free tier; no published SLA or backup schedule

Last verified: 2026-08-18.

restore-into.sh takes any of them — it only wants a TARGET_DSN.

If the target is freebase.cloud

PostgreSQL 16.2 on port 5432, real wire protocol. pg_restore, psql, Prisma, Drizzle, SQLAlchemy and pgx connect with nothing but a connection string, which is all the restore script requires.

export DUMP_PATH=./backups/20260818-031700.dump
export TARGET_DSN='postgresql://freebase@HOST:5432/mydb'
./examples/restore-into.sh

Sign up, create a session, choose PostgreSQL. No credit card and no expiry countdown — which is the specific thing this repository is about, and also the only claim being made. There is no published SLA, no stated uptime figure and no documented backup schedule, so keep running render-backup.sh against the new host with DATABASE_URL pointed at it. The script does not care who operates the server.

Rollback

restore-into.sh writes only to TARGET_DSN. The Render database is read from and never modified. So:

  • Undo the migration: point the application's DATABASE_URL back at Render and redeploy. Works until you delete the instance or the grace period ends — do not delete it the same day you cut over.
  • Undo the restore: if the target was not empty, the script dumped it before writing and printed the exact pg_restore --clean command to put it back. If the target was empty, drop what was created.
  • Writes made after cutover do not travel backwards on their own. If you need to roll back after live traffic, dump the new host and restore that into Render — the same two scripts, swapped.

Also worth having: MCP access

Unrelated to backups, and the reason this sits under the freebase-cloud org: a freebase.cloud instance is addressable over the Model Context Protocol as well as over port 5432. Mint a token from Settings → MCP against the connection you want exposed; the URL it hands back is the endpoint. With a connection named app you get app_query, app_store, app_list_tables and app_annotate_table, plus PostgreSQL-specific pg_dump / pg_restore / pg_tables helpers.

claude mcp add --transport http app https://freebase.cloud/api/mcp/YOUR_TOKEN

VS Code, in .vscode/mcp.json, with the token prompted rather than committed:

{
  "inputs": [
    { "type": "promptString", "id": "app-token", "description": "freebase.cloud MCP token", "password": true }
  ],
  "servers": {
    "app": { "type": "http", "url": "https://freebase.cloud/api/mcp/${input:app-token}" }
  }
}

Claude Desktop takes the URL through Settings → Connectors → Add custom connector, which is what the Claude setup walkthrough covers; the desktop config file has no remote-HTTP option. The token is a path segment rather than a header, so anything holding the URL can write to the database. Treat it accordingly.

Where this earns its place in a migration: after a restore, asking an assistant to compare app_list_tables against the schema file the backup script wrote is faster than reading two dumps by hand.

Caveats

  • Logical dumps are not physical backups. They are portable and they are not point-in-time. For a small database that is fine; at tens of gigabytes it is slow and you should be on a plan with PITR.
  • pg_dump reads a consistent snapshot but it is not free — it takes locks and it costs I/O. Schedule it off-peak, which is what the 03:17 in the examples is doing.
  • The free tier at the destination is aimed at development, prototyping and small production workloads. Keep taking backups.
  • Do not commit .env or backups/. Both are already in .gitignore here.

Sources


freebase.cloud is an independent service and is not affiliated with Render Services, Inc., Anthropic, Microsoft, or the PostgreSQL Global Development Group.

About

Render Postgres alternative — free Postgres that does not expire after 30 days, plus migration steps

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors