Flask on Render works. That's not the issue. You connect your GitHub repo, set a build command and a start command, and 2-3 minutes later your app is live at yourapp.onrender.com with HTTPS bundled in. The problem isn't getting it deployed—it's understanding what happens after you do.
What You Actually Need Before Hitting Deploy
Forget everything you skimmed past in other tutorials. Three files determine whether this works on the first try: requirements.txt, a start command formatted correctly, and optionally runtime.txt if you need to lock your Python version. Your requirements.txt must include gunicorn explicitly—Flask's built-in server isn't production-grade and Render won't touch it. A minimal setup looks like flask plus gunicorn on separate lines. The start command follows the pattern gunicorn app:app, where the first 'app' is your filename and the second is your Flask instance variable name. Get that colon syntax wrong and your service starts and immediately crashes with no useful error message in the dashboard.
Environment Variables and Postgres Are Straightforward
Once deployed, environment variables live in Render's dashboard under the Environment tab—not in your code. Standard Flask vars like SECRET_KEY, DATABASE_URL, and FLASK_ENV=production go here. Render also offers managed Postgres databases that integrate cleanly via SQLAlchemy: create the database, grab the Internal Database URL from settings, paste it into your environment variables as DATABASE_URL, and you're connected. The catch? Free tier Postgres instances expire after 30 days. For anything beyond experimentation, you need a paid instance or an external provider like Supabase.
The Free Tier Problems Nobody Warns You About
Here's where the tutorial bliss ends. Render's free tier spins down any service that receives no traffic for 15 minutes. When it wakes up—and yes, this happens on every first request after inactivity—it takes roughly 60 seconds to spin back up while Render serves a loading page to your visitors. That alone kills user experience for anything with real traffic. Then there's the 750 instance hours per workspace limit. A single always-on free service consumes all of them before month end. Multiple services share this pool, and when the hours are gone, every free service in that workspace suspends until billing resets.
Ephemeral Filesystem Will Bite You
Any file your Flask app writes to disk during runtime—uploaded images, local SQLite databases, cached content—is deleted on restart, redeployment, or spin-down. This catches developers who assume they can use a local file database for persistence. If your app handles uploads or needs writable storage, external services like AWS S3 or Cloudflare R2 are required. Render offers persistent disks but only on paid plans.
Custom Domain DNS Gotcha
Adding a custom domain triggers a warning to remove any AAAA records pointing to IPv6 addresses. Render's infrastructure is IPv4-only. Leaving AAAA records in place causes intermittent routing failures that only affect users on IPv6 networks—making this bug notoriously difficult to reproduce and diagnose if you don't know what you're looking for.
Key Takeaways
- Gunicorn must be explicitly listed in requirements.txt; Flask's dev server won't run on Render
- The start command syntax is gunicorn filename:instance_variable—mismatch here means silent crashes
- Free tier Postgres expires after 30 days; plan accordingly or pay for persistence
- Cold starts take ~60 seconds after 15 minutes of inactivity, guaranteed on free tier
- Ephemeral filesystem wipes all runtime-written files on any restart or deployment
- Custom domains require removing AAAA records entirely—IPv6 breaks routing here
The Bottom Line
Render makes Flask deployment technically accessible, but the free tier is a minefield of hidden limitations that surface at the worst times. If you're building for production, budget the $7/month Starter plan to avoid cold starts and instance hour anxiety. For hobby projects, know exactly what breaks before you ship—because 11pm debugging sessions after your app silently goes dark aren't fun.