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.
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
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.shYou 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
.sqlyou can diff. - Runs
pg_restore --listover every dump before calling it a success. An unreadable dump is the failure that stays quiet until you need it. - Rotates to the newest
KEEPbackups 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_WEBHOOKon 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.
| 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.
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.
| 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.
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.shSign 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.
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_URLback 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 --cleancommand 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.
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_TOKENVS 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.
- 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_dumpreads a consistent snapshot but it is not free — it takes locks and it costs I/O. Schedule it off-peak, which is what the03:17in 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
.envorbackups/. Both are already in.gitignorehere.
- Deploy for Free — Render Docs — 30-day expiry, grace period, spin-down
- Render Postgres Recovery and Backups — what free instances do not get
- Render Postgres — connection strings, internal vs external
- PostgreSQL 16: pg_dump
- Engine list and signup
- Free PostgreSQL cloud instance
- How to connect Claude to PostgreSQL
freebase.cloud is an independent service and is not affiliated with Render Services, Inc., Anthropic, Microsoft, or the PostgreSQL Global Development Group.