Tutorials lie. Every platform works great in demos with clean test data and zero edge cases. Here's what happens when you throw real users, messy data, and production traffic at them.
Supabase: PostgreSQL with Training Wheels
Supabase is PostgreSQL with auto-generated APIs and real-time subscriptions. If you know SQL, you'll feel at home. If you don't, get ready to learn or watch your app crawl.
Getting started is actually nice: The JavaScript client generates TypeScript types from your database schema. Your IDE autocompletes field names instead of you guessing what exists. This alone beats Firebase's "cross your fingers and hope" approach to data types.
Row Level Security will break your brain: Row Level Security policies control who sees what at the database level. Writing (auth.uid() = user_id)
looks simple until you need complex permissions with table joins. I spent 6 hours debugging why users couldn't see their own posts - turned out my RLS policy had a typo in the table reference. The error messages don't help: "permission denied" could mean anything.
SQL is both blessing and curse: Complex queries work because it's actual PostgreSQL. Want to join five tables and aggregate by date? No problem. Need full-text search? Built in. The catch: you need to know SQL performance tuning or your queries will run like garbage. I've seen developers write queries that scan entire tables because they forgot to add indexes. Supabase doesn't hold your hand here - you get rope to either pull yourself up or hang yourself with.
Firebase: Great for Mobile, Weird for Everything Else
Firebase is Google's attempt to make backend development painless for mobile apps. It succeeds brilliantly until you try to do anything that doesn't fit their narrow vision.
Authentication just works: Firebase Auth handles OAuth, email/password, phone auth, and all the edge cases you forgot about. No implementing password reset flows, no dealing with JWT token refresh. It's genuinely good, which makes the rest more frustrating.
Query limitations will drive you insane: Firestore forces you to think in documents, not relationships. Want to filter users by age AND location? Create a composite index first. Need to show posts with their author's name? Either duplicate author data in every post document or make separate queries and combine them in your app. Coming from SQL, this feels like programming with your hands tied.
Billing surprises are real: Firebase charges per read/write operation. That real-time listener updating every second? Each update counts. I've seen bills jump from $20 to $400 because someone left a listener running on a busy collection. The worst part: no spend caps. Your app can literally bankrupt itself while you sleep.
The NoSQL mind-shift: If you're used to normalized databases, Firestore requires you to duplicate data everywhere. User changes their profile pic? Now you need to update it in posts, comments, and user documents. Miss one update, and your data is inconsistent. There's no CASCADE UPDATE to save you.
AWS Amplify: Enterprise Power with Enterprise Complexity
AWS Amplify connects you to Amazon's entire service catalog. If you love complexity and have AWS experts on your team, it's incredibly powerful. If you're new to AWS, prepare to hate your life for a few months.
Configuration nightmare: Run amplify init
and watch it generate 47 CloudFormation files for what should be a simple API. The CLI creates IAM roles with names like amplify-todoapp-dev-20210301-authRole-1ABCD2EFGH
. Good luck figuring out what anything does when something breaks. I spent two days debugging why my Lambda couldn't read from DynamoDB - turned out the auto-generated IAM policy had a typo in the resource ARN.
Scaling is genuinely impressive: When properly configured, Lambda functions handle traffic spikes flawlessly, DynamoDB serves millions of requests per second, and CloudFront caches your content globally. The integration between services is seamless - once you understand how the 47 moving parts work together.
Debugging is AWS hell: Error messages reference internal AWS states, not your application. "Deployment failed" could mean anything: CloudFormation rollback, service quota exceeded, IAM permission denied, or Lambda timeout. You'll become an expert at reading CloudWatch logs whether you want to or not. The debugging process assumes you know AWS's 200+ services and how they interact.
Appwrite: Self-Hosted Backend Services
Appwrite gives you Firebase-like features without the vendor lock-in. You own your data and infrastructure, which means you also own every 3am outage and security patch.
Local development is smooth: Run docker-compose up
and you get a complete backend stack - database, auth, storage, functions, everything. The Docker setup actually works, which is more than I can say for most self-hosted solutions. Development feels fast and reliable because everything runs locally.
SDKs are surprisingly consistent: Unlike Firebase where iOS, Android, and web SDKs all work differently, Appwrite's SDKs use identical patterns across platforms. Create a user, upload a file, query documents - same code structure everywhere. This is genuinely nice when you're context-switching between frontend and mobile.
You're the ops team now: Self-hosting means you handle SSL certificate renewals, database backups, security updates, load balancing, monitoring, log rotation, and disaster recovery. When Redis runs out of memory at 2am, you're the one getting paged. When the disk fills up with logs, that's your problem. The flip side: when something breaks, you can SSH in and fix it instead of filing a support ticket and hoping.
Multi-Developer Reality Check
Here's what actually happens when you're not working alone anymore and suddenly need to coordinate with other humans who have their own ideas about how databases should work.
Schema changes expose team chaos: Supabase handles schema changes like a real database - with migrations you can review in pull requests. Firebase's "just change the structure whenever" approach works until Sarah from frontend renames userId
to user_id
and breaks the mobile app. Nobody knows what fields exist because there's no schema to check. Good luck finding all the places that reference the old field name.
Environment hell is real: AWS Amplify gives you proper staging environments that actually match production - if you can decode the CloudFormation. Firebase's environments are "production" and "production-with-fewer-users." Appwrite lets you spin up unlimited environments, but you're manually configuring SSL certs and load balancers for each one. At 11pm. Because the deployment pipeline broke again.
Testing reveals the lies: Supabase's PostgreSQL lets you test complex queries locally with real data. Firebase's emulator suite pretends to work like production but real-time listeners randomly disconnect in ways that never happen locally. AWS testing means learning which of their 47 testing services actually matter - spoiler: most don't.
When your team grows past "two people who sit next to each other," these platform differences become the reason deploys take three hours and everyone's stressed. The tools that felt clever with one developer become coordination nightmares with five.