Replit is great for building stuff fast. You can go from blank screen to working app before your coffee gets cold. That part is excellent.
It's also a terrible place to keep production data.
Not because Replit is "bad." Replit is doing its job: a managed, containerized environment that can restart, move, update, and clean itself up. That's fine for code. That's a disaster for the one thing your users will never forgive you for losing: their data.
Developer confidence is a system, not a vibe
I like boring database setups because I've been woken up at 3 AM too many times. Boring means: automated backups, tested restores, migrations that don't make you cry, and logs that actually tell you what happened.
Developer confidence isn't "I'm smart so this will work." It's confidence in a process that assumes you'll do something dumb under pressure and still recover.
- automated backups
- tested restores (yes, tested)
- migrations you can run twice without crying
- logs that tell you what happened without playing detective for three hours
I ran a migration once with a typo. Dropped the entire billing table instead of altering it. Not "oops, wrong column" - the whole table, gone.
Three hours of downtime. Restoring from backups, recovering from binary logs, production alarms going off. The fix wasn't me being clever. The fix was having backups that actually worked and enough logging to know what to restore.
Replit databases: fine for demos, risky for real users
If your app is a toy, use whatever you want. If your app has real users, money, or even mild emotional attachment, don't store the source of truth inside an environment that can disappear.
Here's what actually happens:
- You build "just a test app."
- You use SQLite or a little embedded DB because it's easy.
- Someone tweets it.
- Now you have 500 users creating data while you're still thinking in prototype mode.
- Now you're doing a rushed migration while the plane is in the air.
This isn't a moral failing. It's just what happens when you ship things. People actually use them.
Replit also doesn't hand you a real backup/restore story. You can build one, sure. Most people don't. And even fewer people verify that a backup can restore cleanly. A backup you never restored is a comforting bedtime story.
Use AWS RDS for the database. Keep Replit for the app.
If you want production-grade data with minimal drama, use a managed database like AWS RDS. You're paying AWS to handle the mechanical stuff: storage, backups, patching, and a control plane built for data that actually matters.
Quick setup (MariaDB example)
- Go to https://console.aws.amazon.com/
- Search RDS
- Click Create database
- Pick an engine:
- MariaDB: my default from my Rackspace DBA days. It's MySQL without Oracle, maintained by people who actually care about it. Fast, stable, well-documented.
- PostgreSQL: great if you need stricter constraints, better JSON, PostGIS, etc.
Pick a small instance to start. I've seen companies spend hundreds per month on instances serving maybe 10 queries an hour. You can always scale up later.
- Staging:
db.t3.micro(often free tier) - Small prod:
db.t3.small
Storage: start at 20GB, enable autoscaling up to 100GB so you don't wake up at 3 AM because disk is full.
Backups: enable automated backups.
- Staging: 7 days
- Production: 30 days
- Turn on point-in-time recovery. Costs a few cents monthly. Worth every penny when you need to restore to 2:46 PM because someone deleted data at 2:47 PM.
Connectivity: the part everyone messes up
For staging, you'll probably need Public access: YES, because Replit is outside AWS.
Then lock it down with a security group rule. For quick staging you can do:
- Port:
3306(MariaDB/MySQL) - Source:
0.0.0.0/0
Yes, this is open to the world. It's a practical tradeoff for staging with Replit. For production, lock it down properly: restrict by IP, use a VPN, a bastion host, or PrivateLink. Don't leave prod wide open unless you enjoy log files full of strangers trying root:password.
Put the connection string in Replit Secrets
Your endpoint will look like:
myapp-staging-db.abc123.us-east-1.rds.amazonaws.com
Store a DATABASE_URL secret like:
mysql://user:pass@myapp-staging-db.abc123.us-east-1.rds.amazonaws.com:3306/myapp_staging
Then in Python:
import os
DATABASE_URL = os.environ["DATABASE_URL"]
Never commit this to git. Not once, not "just for testing," not ever. Your code needs to live somewhere other than your laptop, but your secrets don't belong in version control.
Two settings you'll regret skipping
Use utf8mb4
MySQL's utf8 is a lie. It only supports up to 3 bytes per character, which excludes most emojis. utf8mb4 is actual UTF-8 with up to 4 bytes per character. Your users WILL use emojis in their names.
Use:
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
Don't skip foreign keys
People skip foreign keys because they heard it "slows things down." Debugging corrupt data slows things down more.
If you have orders.user_id, enforce that the user exists. Your future self will be less furious at 2 AM.
The point: set up boring once, then move fast
Set up the boring infrastructure once. Then you can move fast on everything else without worrying about losing data.
Sethers