Blog / Web Engineering
How to Deploy Your First Full-Stack App for Free
No credit card, no trial period that quietly starts billing you — a real stack for putting a frontend, backend, and database on the internet for free, plus the specific ways free tiers bite you later.
"I don't know how to deploy this" kills more finished side projects than any bug ever does. The code works on localhost, it's been working for weeks, and it just... never goes anywhere, because deployment feels like a separate, scarier skill from the one you just spent a month practicing. It isn't, and none of the layers of a real full-stack app — frontend, backend, database — actually require a credit card to run for real today.
The frontend layer
If your frontend is static or server-rendered at build time — plain HTML and JS, or something like Astro, a statically-exported Next.js app, or a Vite-built single-page app — GitHub Pages, Vercel, Netlify, and Cloudflare Pages all offer free tiers that include a CDN, automatic HTTPS, and deploys triggered directly by a git push. For a fully static site, "deploying" can genuinely be nothing more than pushing to a branch and letting a GitHub Action build and publish it for you, with no server to manage at all.
The backend layer, and how to pick between the options
The right choice here depends less on what's "best" and more on how your app actually runs. If it's a lightweight API that doesn't need a long-lived process — a handful of endpoints that each do one thing and return — serverless functions on Vercel, Netlify, or Cloudflare Workers are a strong fit, with request quotas generous enough for a real first project's traffic.
If you need a small, persistent server — something with in-memory state, a WebSocket connection, or a background job — Render and Railway both offer free-tier web services. The honest caveat: free instances on both typically sleep after a period of inactivity and take a few seconds to spin back up on the next request, which is a fine tradeoff for a portfolio project and a genuinely bad one for a live demo you're presenting to someone in real time.
And if you want a real, always-on server without giving anyone a card number, Oracle Cloud's Always Free tier includes small compute instances that don't expire and don't sleep — it's more setup than a managed platform, but it's worth knowing exists for the specific case where "sleeps after inactivity" isn't acceptable and you're not ready to pay for uptime.
The database layer
For Postgres, Supabase and Neon both offer a genuinely production-usable free tier — a real dashboard, connection pooling, and enough storage for a first project to grow into rather than immediately outgrow. For MongoDB, Atlas's free shared cluster comfortably covers a real first project's traffic. And if you don't need a heavier relational database, Turso offers a free tier for distributed SQLite that's a good, lightweight fit for smaller apps.
Secrets and environment variables in a deployed app
A mistake specific to first-time deployment: code that reads secrets from a local `.env` file works perfectly on your machine and then fails mysteriously the moment it's deployed, because the `.env` file — correctly — never got committed to the repository, and the hosting platform has no way to know what values it contained. Every platform mentioned above has its own dashboard or CLI for setting environment variables directly on the deployed service, separate from your codebase entirely, and this is where API keys, database connection strings, and secrets actually belong once an app goes live. Get in the habit of checking your hosting platform's environment variable settings the moment a deploy fails with a config-related error — it's a far more common cause than an actual code bug at this stage.
Custom domains and why they're easier than they sound
A free subdomain from your host — `your-project.vercel.app`, `your-project.onrender.com` — is completely fine for a first project, and there's no rush to change it. If you do want your own domain later, every major platform supports adding one for free once you own it (the domain itself typically costs somewhere around ten to fifteen dollars a year from a registrar, which is the one genuinely unavoidable cost in this whole stack if you want it). The process is almost always the same shape: add the domain in your hosting platform's dashboard, then add the DNS records it gives you at your domain registrar, and wait for DNS to propagate, usually within an hour.
Putting a whole stack together
A concrete example that costs nothing and is genuinely production-viable for a first real project: an Astro or static frontend on Cloudflare Pages, a small API on Render's free web service tier, and Supabase handling both Postgres and authentication. That's a complete, publicly reachable, full-stack app — deployable in an afternoon, with no invoice at the end of the month.
# A typical free-tier deploy flow
1. Push frontend to GitHub -> CI builds and deploys to Pages/Vercel/Netlify
2. Push backend to GitHub -> Render/Railway auto-deploys on push
3. Point the backend at your free Postgres/Mongo instance via env vars
4. Set the frontend's API base URL to the deployed backend's URLA basic monitoring habit, even on free infrastructure
It's tempting to treat monitoring as a "real production app" concern that a free-tier side project doesn't need yet, and mostly that's true — but it's worth at minimum knowing where your deployed app's logs actually live before something breaks, not while it's broken and a stranger is refreshing a page that's returning a 500. Every platform above has a logs tab in its dashboard; the specific habit worth building is checking it once, on a working deploy, so you know what normal output looks like and can actually recognize an error when one shows up later.
Where free tiers actually hurt, honestly
Cold starts are the one that catches people off guard in exactly the wrong moment: a serverless function or a sleeping free-tier server adds a real, noticeable delay to the first request after idle time. That's invisible during normal development, where you're hitting the app constantly and it never goes to sleep — and then it shows up live, in front of an interviewer or a judge, as an awkward five-second pause on the first click. If you're demoing something important, "wake it up" by hitting it yourself two minutes before anyone else does.
Storage and bandwidth caps are the slower-moving risk — free database tiers usually cap you in the low single-digit gigabytes, which is plenty for a first project's entire lifetime but worth glancing at occasionally as usage actually grows, rather than discovering the cap the moment you hit it. And there's no SLA on any of this: free tiers do have real outages, with no guaranteed uptime and nobody to escalate to. Don't put anything genuinely time-critical on one without a fallback plan you've actually thought through.
The path from free to paid, when you actually need it
Every platform in this stack is designed so that outgrowing the free tier is a config change, not a migration — the same Render service upgrades to a paid instance that doesn't sleep with one click, the same Supabase project scales to a larger Postgres instance without a data migration. The point of starting on free infrastructure was never to stay there forever if the project takes off; it's that the architecture you build on day one, on the free tier, is the same architecture that scales, so nothing about starting free costs you a rebuild later.
The point of deploying on free tiers was never to run serious production traffic on them forever. It's to permanently remove "I don't know how to host this" from the list of reasons a finished project never sees the internet.