What is the best Flask hosting in 2026?
Flask decides nothing for you, so the answer depends on how much has grown around it. For one file and one route, PythonAnywhere at $10/month is the gentlest possible start and Render's free tier the cheapest place to park it. Fly.io keeps a small app online from about $2/month once the free tier's spin-down becomes annoying.
Granite — our own platform — is $9/month with $15 of usage credits, and makes sense once Flask has grown SQLAlchemy against a real Postgres, a Celery queue and uploads that need somewhere to live.
Last updated 1 September 2026
There is no such thing as a typical Flask application, and that is the whole difficulty of writing this page. Flask is a microframework: it gives you routing, request handling and templates, and leaves the database, the migrations, the authentication, the background jobs and the file storage to you. Two projects with the same import line can have completely different hosting requirements.
So the useful way to read the table below is by what your application has grown. A stateless service that returns JSON fits the cheapest tier of any platform here. Add SQLAlchemy and you need a managed Postgres you are not personally responsible for. Add Celery and you need somewhere to run a process that is not a web server. Add uploads and you need object storage. Each of those moves the answer, and none of them is about Flask itself.
The one thing every deployment shares is that the development server is not a production server. Flask says so on startup, and it is the single most common way a first deployment goes wrong: one request at a time, no timeouts, a debugger that executes arbitrary code if debug mode survives into production. Every platform below expects you to bring gunicorn, uWSGI or waitress.
The short version: PythonAnywhere is the gentlest possible start, Render has the most usable free tier, Fly.io is the cheapest way to keep a small app online, and Granite — our own platform — makes sense once Flask has grown a database, a queue and somewhere to put uploads. If it is still one file and one route, we are the wrong answer and the table shows it.
How much does Flask hosting cost?
| Provider | From /mo | Free tier | Managed DB | Persistent disk | Deploy from |
|---|---|---|---|---|---|
| Fly.io | ~$2 | Postgres (unmanaged app) | Dockerfile, buildpack | ||
| Railway | $5 | yes ($1 credits) | Git, Dockerfile, template | ||
| Render | $7 | yes (spins down) | Git, Dockerfile | ||
| Granite | $9 | from Advanced | Git, Docker image | ||
| PythonAnywhere | $10 | yes (limited) | MySQL | yes (5 GB) | Git pull, web UI |
| Koyeb | $29 | limited | Serverless Postgres | Git, Dockerfile | |
| Google Cloud Run | usage-based | yes (monthly allowance) | via Cloud SQL | no (use GCS) | Container image |
Entry prices as published by each provider on 1 September 2026, sorted cheapest first. Usage, bandwidth and databases are billed on top almost everywhere — treat this column as a starting point, not a monthly bill.
PaaS, serverless or a plain VPS?
A VPS is always cheaper per gigabyte, and for Flask the gap is narrower than for heavier frameworks simply because you need fewer gigabytes. What a platform sells is everything around gunicorn: TLS and its renewal, zero-downtime rollouts, log collection, and database backups someone else is responsible for restoring. If the app is a hobby and you enjoy the machine, a VPS is a perfectly honest answer.
Serverless fits Flask better than it fits Django, for the same reason Flask exists: there is less to import. A small app boots in about a second rather than several, which makes scale-to-zero tolerable for internal tools and bursty APIs. The catch is not the cold start but the assumptions a small app tends to carry — a SQLite file on disk, uploads in a folder, a scheduler thread — none of which survive a platform with no filesystem and no long-lived process.
A managed platform earns its place at a specific moment: when the application acquires its second process. A web server plus a Celery worker plus a beat scheduler is three things that must share code and secrets and deploy together, and doing that by hand is where evenings go.
One file, no database, or you have never deployed anything before
PythonAnywhere or a free tier
Live in an afternoon, with nothing to configure and nothing to pay.
PythonAnywhere · Render free
SQLAlchemy, migrations, uploads and probably a Celery worker
Managed platform
Web, worker and beat deploy together, beside a Postgres you do not operate.
Granite · Railway · Render
Stateless service, idle most of the day, no long-lived processes
Serverless
Free while idle, and Flask's short import graph keeps the cold start bearable.
Cloud Run · Koyeb
What does each platform actually give you?
Fly.io
- Best for
- The cheapest way to keep a small Flask app online, especially a stateless one.
- Pricing
- Pay as you go. The smallest shared-cpu-1x machine with 256 MB RAM works out at roughly $2.02/month, billed per second.
- Cheapest entry point in this table, and a modest Flask app genuinely fits a 256 MB machine — unlike Django, where the same tier is a squeeze.
- Takes your Dockerfile, so the Python version and the WSGI server are entirely yours to pin.
- Multi-region and per-second billing are first-class.
- Postgres is a Fly app you operate and back up yourself, which is a real commitment the moment the app stops being stateless.
- You manage more infrastructure — machines, volumes and networking are exposed concepts.
- No free tier for new organisations since October 2024.
Railway
- Best for
- Assembling Flask, Postgres and Redis quickly without deciding anything in advance.
- Pricing
- Billing is per second of actual usage against a monthly minimum: $5 on Hobby and $20 on Pro, each including that much usage credit. The free plan is a 30-day trial with $5 of credits and $1 a month afterwards, capped at 1 vCPU and 0.5 GB per service. Pro includes unlimited workspace seats.
- Detects a Python project and runs it without configuration.
- Databases and Redis sit alongside services in the same project, so Celery has a broker within reach.
- A free plan and a 30-day trial for evaluation.
- Usage-based billing on top of the base fee makes the monthly cost hard to predict.
- Hobby is limited to one developer per workspace; collaborating means the $20/month Pro minimum, not the $5 one.
Render
- Best for
- A free home for a small Flask app, and a simple paid tier once it earns one.
- Pricing
- Free web services are available but spin down after 15 minutes without traffic. The cheapest paid instance, Starter, is $7/month for 0.5 vCPU and 512 MB RAM.
- A genuine free tier for web services, which suits Flask's usual scale better than most.
- Managed Postgres, background workers and cron jobs in one account, which covers Celery and beat.
- Straightforward fixed instance pricing after the free tier — no credits to reason about.
- Free services spin down after 15 minutes idle; a Flask cold start is a second or two rather than Django's several, but the first visitor still waits.
- Costs climb once you need more than one small instance.
Granite
- Best for
- A Flask application that has grown a database, a queue and file uploads, and wants them in one project.
- Pricing
- Hobby is $9/month and includes $15 of monthly usage credits. Advanced is $39/month with $50 of credits, Professional $149/month with $200. Every plan has unlimited workspace seats.
- Managed Postgres, MySQL and Valkey run in the same project over internal DNS — the database and the Celery broker without a connection string leaving the cluster.
- S3-compatible storage with a CDN is where uploads belong once the container filesystem stops being trustworthy, which is immediately.
- Web app, Celery worker and beat are three resources from one image, so they share code, secrets and deploys.
- Unlimited workspace seats on every plan, and flat pricing that does not move with traffic.
- No free tier — the cheapest way in is $9/month, which is hard to justify for a single-file app.
- Persistent volumes start on the Advanced plan.
- Nothing here is Python-specific: there is no hand-holding if this is your first deployment.
PythonAnywhere
- Best for
- A first deployment, a teaching project or a small internal tool, where simplicity beats control.
- Pricing
- A limited free Beginner account runs one web app with restricted outbound internet. The Developer plan is $10/month: one web app on a custom domain, 5 GB of storage and 5,000 CPU-seconds a day.
- Built around Python and WSGI specifically, which is exactly what Flask is — you edit a WSGI file and the site is live, with no Docker and no build pipeline.
- A free tier that serves a real Flask site on a subdomain, which is genuinely useful for coursework and demos.
- MySQL and scheduled tasks are included rather than assembled.
- You work inside their environment rather than your own container, so anything unusual in your stack may simply not be possible.
- Background processing is limited — Celery is awkward here, and scheduled tasks are the intended answer.
- The free tier restricts outbound internet access to an allowlist, which breaks apps that call third-party APIs.
Koyeb
- Best for
- Edge presence with scale-to-zero for an app that is idle most of the day.
- Pricing
- Pro is $29/month plus compute and includes $10 of it; Scale is $299/month including $100. Serverless Postgres has a free tier of 5 hours a month at 0.25 vCPU, 1 GB RAM and 1 GB of storage, after which the smallest always-on instance is $29.76/month plus $0.50 per GB stored.
- Edge locations included rather than sold separately.
- Managed Postgres available without leaving the platform.
- The highest entry price of any managed option here, which is a strange fit for a framework people usually choose to keep things small.
- Scale-to-zero means the first visitor after an idle period pays for the interpreter to boot.
Google Cloud Run
- Best for
- A stateless Flask service with spiky traffic, for teams already in GCP.
- Pricing
- No monthly fee. You pay per request and per resource-second, with a monthly free allowance. Cloud SQL and networking are billed separately.
- Scales to zero, so an idle service is genuinely free — and Flask's small import graph makes the cold start shorter than Django's.
- Takes any container image, so a slim multi-stage build applies unchanged.
- Effectively unlimited scale ceiling.
- No persistent disk, so uploads and any SQLite file must move before you deploy at all.
- Postgres, secrets and networking are separate GCP products you assemble and bill separately.
- Every instance opens its own connection pool, so autoscaling multiplies your database connections.
What does a Flask app need from a host?
- Bring a WSGI server
- flask run is a development server: single-threaded by default, no request timeouts, and a debugger that will execute code sent by anyone who reaches it. Production means gunicorn, uWSGI or waitress with an explicit worker count — and a platform that lets you set the start command rather than guessing one for you.
- A stable SECRET_KEY
- Flask signs session cookies with it. Generate it once, store it as an environment variable, and never let the application invent one at startup: a fresh key per deploy silently logs out every user, and a different key per replica logs them out at random. It is the most confusing bug in this list because the application looks completely healthy.
- The app factory and the entrypoint
- Most non-trivial Flask projects use a create_app factory, and the platform needs to be told how to reach it — wsgi:app, app:create_app() or a module you provide. Platforms that auto-detect Python often guess app.py and nothing else, so check that the start command is yours to write.
- Migrations as a release step
- flask db upgrade must run once per deploy, after the build and before the new version takes traffic. In the container start command every replica races to migrate the same schema at the same time. Look for a release command or pre-deploy hook and treat its absence as a real limitation.
- SQLite does not survive
- Flask tutorials reach for SQLite, and it is genuinely fine locally. On any container platform the filesystem is discarded on deploy and not shared between replicas, so the database quietly resets or diverges. Move to managed Postgres or MySQL before the first real user, not after.
- Uploads belong in a bucket
- The same problem in a different costume: files written to a local folder disappear on the next deploy and are invisible to a second instance. A persistent volume works for a single instance; S3-compatible storage works for any number and puts a CDN in front of them.
- Somewhere for Celery
- If there is a queue, you need a long-running worker process, usually a beat scheduler, and Redis or Valkey as a broker. A platform that only runs web services means renting something else for this — and a scheduler thread inside the web process is not a substitute once there are two replicas.
- Memory per worker, not per request
- Each gunicorn worker is a separate process holding the interpreter and your application, so memory tracks worker count rather than traffic. Flask's floor is meaningfully lower than Django's — there is less framework to load — which is why the smallest tiers stay realistic here for longer.
Where do background jobs and queue workers run?
Outside the request, and outside gunicorn. A thread spawned inside a view is bound to a worker process that the platform may recycle at any moment, so the honest options are Celery with a Valkey or Redis broker, or RQ if one queue and one Redis is the whole requirement. The consumer is a separate long-lived process — celery -A app.celery worker or rq worker — built from the same image as the web app so the task code and the view code cannot diverge. On Granite it is a worker resource in the same application, with the broker as a managed Valkey alongside it. When a deploy takes the container away, an unacknowledged task returns to the queue and runs again, so a task that charges a card twice is a bug you have to design out.
How do scheduled tasks and cron work?
APScheduler started inside the app is the shortest path and the one that misbehaves under load: the scheduler lives in every gunicorn worker in every replica, so a nightly export runs four times on one container and twelve across three. Either give it a jobstore with locking, or move the schedule out of the process entirely. A platform cron is the cleaner version — on Granite a cron-job resource runs flask export-reports on a cron expression as a single container, with Forbid or Allow governing an overrunning run, and its output goes to that resource's log rather than into the web app's stream.
Is Postgres managed, and what about backups?
Managed on Render, Railway, Koyeb and Granite, an app you run yourself on Fly, and a separate Cloud SQL product on Cloud Run. Granite takes backups on a schedule into external storage and support can run point-in-time recovery for Postgres on request; the interval is not published, so ask before you depend on it. Databases have no public endpoint — the app connects over internal DNS, you connect via novps port-forward database <id> -l 5432. SQLAlchemy's pool is per process, not per application, so a pool_size of five across four gunicorn workers is twenty connections from a single service, and a pooler in front of the database is what stops that becoming an outage.
How do deploys and migrations work?
A push to the tracked branch builds an image and rolls it out, or the platform watches a Docker tag you push yourself. flask db upgrade has to run exactly once per deploy: Render and Railway expose a release command for it, and on Granite you run it from the resource's Console tab or over a forwarded database port before the new image goes live. In the container start command it becomes a race between replicas against one schema. Keep in mind that a rollback restores the image and not the database, so a migration that drops a column takes the previous version down with it.
What does it actually cost per month?
A web service, an RQ or Celery worker, a small Postgres and a broker, as of 1 September 2026. Render totals $30 — $7 web, $7 worker, $6 for a 256 MB Postgres, $10 for a 256 MB Key Value instance. Fly.io is $3.32 for each 512 MB machine, with the database your responsibility. PythonAnywhere is $10 and includes scheduled tasks, but not a real queue. Granite is $9 with $15 of credits spread across all four pieces, $8 of which the Extra Small Valkey node takes — and Hobby's 1 GiB per service holds a small gunicorn set rather than a generous one.
So which should you pick?
Your first ever deployment, or a teaching project. PythonAnywhere. It hides everything you are not ready for, and the free tier serves a real site on a real URL.
A small app that should cost nothing. Render's free tier, accepting the spin-down after fifteen idle minutes.
The cheapest way to keep something small always on. Fly.io, at roughly $2/month. Flask is one of the few frameworks where that headline price genuinely applies rather than being a footnote.
Flask that has grown a database, a queue and uploads. This is where we would argue for Granite. Postgres or MySQL and Valkey run in the same project with no public endpoint, S3-compatible storage with a CDN gives uploads a permanent home, and the web app, the Celery worker and beat are three resources from one image that deploy together. From $9/month with $15 of usage credits.
Comparing Python frameworks rather than platforms? The Django and FastAPI comparisons cover the same providers with different conclusions, and the app platform page covers workers and cron jobs in detail.
Hosting for other stacks
Six ways to run a Go binary, from a $2 machine to scale-to-zero — and why Go stays cheap longer.
Seven options weighed on the things Django actually needs: media storage, a real Postgres, Celery workers and enough memory for gunicorn.
Vercel and six alternatives, weighed on the things that actually break when you self-host: ISR across replicas, image optimization and build-time env vars.
Six ways to run an Express, NestJS or Fastify service — weighed on the event loop, the connection pool, and what a long-lived process costs while it waits.
Six platforms plus Kamal, weighed on what Rails really needs: a release phase for migrations, a job runner, Active Storage and enough memory for Puma.
Laravel Cloud and six alternatives, weighed on queue workers, the scheduler, writable storage and the caches you must rebuild on every deploy.
Seven platforms for Django, Flask, FastAPI or a script with no HTTP port at all — and how to tell which of those you are actually deploying.
Six platforms weighed on what an ASGI service actually needs: worker processes, connections that stay open, and a database pool that does not multiply out of control.
Six platforms weighed on the things Symfony assumes: a warmed cache built at build time, Messenger workers that restart on deploy, and Doctrine migrations that run exactly once.
Seven platforms for a framework that renders on every request — weighed on streaming, adapters, and how far the loaders sit from the database.
Six platforms weighed on what the JVM actually asks for: memory it is allowed to use, a container that knows its own limits, and a start-up you can afford to repeat.
Six places to run a container image, compared on what actually bites: architecture mismatches, registry access, signal handling and the volume you assumed would still be there.
Five ways to serve HTML that is already written — and an honest note about which of them we are not the right answer for.