DEV Community

niuniu
niuniu

Posted on

I Moved 7 Side Projects from AWS RDS to Free Postgres — My Bill Went from $47/Month to $0

I had 7 side projects on AWS RDS. None had more than 100 users. All were quietly costing me $6-8/month each — $47/month for databases that served maybe 50 requests per day combined.

I spent a weekend migrating them all to free-tier Postgres. Here's what happened.

The inventory (before)

Project DB size Requests/day RDS cost
URL shortener 12MB ~20 $6.80
Blog comments 3MB ~5 $6.80
Habit tracker 8MB ~15 $6.80
Recipe box 45MB ~30 $7.20
Weather cache 120MB ~50 $8.40
API status page 2MB ~10 $6.80
Wedding RSVP (archived) 5MB 0 $6.80
Total 195MB ~130 $47.60

The migration targets

  • Neon: 0.5GB free, autosuspend, branching. Best for projects that need to wake fast.
  • Supabase: 500MB free, connection pooler, auth built-in. Best for projects needing auth.
  • Turso: 9GB free, sqlite-vec, edge replicas. Best for read-heavy, tiny latency.

The migration script (works for any Postgres)

#!/bin/bash
# migrate.sh — dump from RDS, restore to free tier
set -e

SOURCE="postgres://user:pass@rds.amazonaws.com:5432/dbname"
TARGET="postgres://user:pass@ep-xxx.neon.tech/dbname"

# Dump with no owner, no privileges (cleanest for free tiers)
pg_dump "$SOURCE" \
  --no-owner --no-privileges --no-tablespaces \
  --format=custom --file=/tmp/dump.backup

# Restore
pg_restore --dbname="$TARGET" --no-owner --no-privileges /tmp/dump.backup

echo "Done. Verify row counts:"
psql "$TARGET" -c "SELECT schemaname, relname, n_live_tup FROM pg_stat_user_tables;"
Enter fullscreen mode Exit fullscreen mode

Gotchas that cost me 3 hours

  1. Neon autosuspend kills long queries. My recipe box had a materialized view refresh that took 90 seconds. Neon killed it at 30s. Fix: SET idle_in_transaction_session_timeout = 0 and run refreshes during active hours.

  2. Supabase pooler drops idle connections. My habit tracker's background worker used a persistent connection. After 10 minutes idle, Supabase dropped it. Fix: switch to connection pooler in transaction mode, or use pgbouncer.

  3. Turso is SQLite, not Postgres. My weather cache used jsonb_path_query. Turso doesn't have it. I rewrote to plain JSON functions. Not hard, but not a drop-in replacement.

The results (after 30 days)

Project New home Cost Uptime Notes
URL shortener Neon $0 100% Cold start ~300ms, fine
Blog comments Supabase $0 100% Auth integration was free
Habit tracker Neon $0 99.2% One 4-min outage during region failover
Recipe box Turso $0 100% Fastest of all, edge replicas help
Weather cache Turso $0 100% JSON rewrite took 1 hour
API status page Supabase $0 100% Cron pings keep it warm
Wedding RSVP Neon $0 100% Dormant, autosuspend is perfect

Total: $0/month. Savings: $571/year.

The controversial part

AWS RDS free tier is a trap for side projects. 12 months free, then $6-8/month per project forever. The free tiers from Neon, Supabase, and Turso are permanent and generous enough for anything under 100 daily users. The lock-in isn't technical — it's the migration script above. Run it once, you're free.

Migration configs and monitoring scripts drafted with MonkeyCode: https://ly.cyberserval.tech/iIETXiF

Which project are you keeping on paid RDS that could be free? And what's actually stopping you from migrating it this weekend?

Top comments (0)