A full-stack app on free tiers, without a card

October 25, 2026 · 5 min read

The PSA FAU Community Forum is a moderated Q&A forum for the Pakistan Student Association community at FAU Erlangen-Nürnberg. My friend Abdul Moeez and I built it over one weekend in October 2026. At most it will have 1,000 to 1,500 users. It runs on free tiers, it costs 0 EUR today, and none of the accounts behind it has a card on file.

The only spend we plan is a domain, about 10 EUR a year. This is how the pieces fit, what each free tier quietly asks of you in return, and when I'd actually start paying. The forum is the example, but the shape works for most small apps with a frontend, a backend and some files.

Each free tier does one job

The frontend and the server functions run on Vercel Hobby. The app is Next.js 16 with the App Router; pushes to main deploy, and pull requests get preview deployments. Postgres and auth live on Supabase Free: Postgres 17, Google sign-in and email magic links, and row-level security doing the authorization.

Files go to a private Backblaze B2 bucket and reach the browser through a Cloudflare Worker. That part is designed and being built, not live yet. Auth emails leave through a Gmail account's SMTP, and Cloudflare Turnstile keeps bots away from the email sign-in. GitHub Actions does everything on a schedule: CI on every pull request, a job that keeps the database awake, and a nightly backup.

Your users
  • Browser

    visitors and members

Edgee.g. Cloudflare Workers
  • Edge worker

    serves the files

    100k req/day

    catch: fails past the limit

Appe.g. Vercel Hobby
  • Frontend

    pages + server functions

    1M calls/mo

    catch: non-commercial only

Bot checke.g. Turnstile
  • Bot check

    guards sign-in

    free
Emaile.g. Gmail SMTP
  • Email

    magic links

    ~500 mails/day

    catch: needs an app password

Datae.g. Supabase Free
  • Database

    Postgres

    500 MB

    catch: pauses after 7 idle days

  • Auth

    sign-in, sessions

    50k MAU

    catch: mailer: a few an hour

Storagee.g. Backblaze B2
  • Object storage

    private buckets for files and backups

    10 GB freeegress to Cloudflare: free

    catch: past 10 GB needs a card

Schedulede.g. GitHub Actions
  • Scheduled jobs

    CI on every PR · keep-awake · nightly backup

    free for public repos

    catch: public repo: never upload a backup as an artifact

How it connects

  1. Browser → Frontend → Database

    Cache public pages, so one query serves every visitor.

  2. Browser → Bot check → Auth → Email

    Sign-in carries a bot-check token; auth verifies it and sends the link through your own SMTP.

  3. Browser → Frontend → Object storage

    Uploads go through your server with a read-write key, never straight to the bucket.

  4. Browser → Edge worker → Object storage

    Files are read through the worker with a read-only key.

  5. Scheduled jobs → Database

    Read one row every 3 days to stay awake; dump the data every night.

  6. Scheduled jobs → Object storage

    The encrypted dump goes to storage with a write-only key.

  • request or data
  • scheduled
Each box is a role, with the free tier we use for it as the example, its main limit and its catch. Files reach the browser through the edge worker, never straight from the bucket. Dashed paths run on a schedule.

Here's how the forum wires it together, with its regions and the nightly backup.

Members
  • Browser

    PSA FAU members · 1,000–1,500 at most

EdgeCloudflare Workers
  • Media Workerin progress

    workers.dev for now

    100k req/day
AppVercel Hobby
  • Next.js 16

    London · lhr1

    1M calls/mo
Bot checkCloudflare Turnstile
  • Turnstile

    guards email sign-in

    free
EmailGmail SMTP
  • Gmail SMTP

    magic-link emails

    ~500 mails/day
DataSupabase Free · London eu-west-2
  • Postgres 17

    row-level security

    500 MB
  • Auth

    Google + magic links

    50k MAU
  • Realtime

    new notifications

StorageBackblaze B2 · EU Central (Amsterdam) · 10 GB shared
  • Images bucketin progress

    private · stop at 8 GB

  • Backups bucket

    daily/ · weekly/

    write-only key
ScheduledGitHub Actions
  • Nightly backup · 02:30 UTC

    pg_dump → gzip -9 → age, then upload

    free · public repokeep-awake every 3 days

How it connects

  1. Browser → Next.js → Postgres

    Public pages read through a cookieless client inside "use cache", so one result serves every visitor. Functions run in London next to the database.

  2. Browser → Turnstile → Next.js → Auth

    Email sign-in carries a Turnstile token; Supabase verifies it.

  3. Auth → Gmail SMTP → Browser

    The magic link leaves through Gmail, about 500 a day.

  4. Postgres → Realtime → Browser

    A new notification is pushed to the bell.

  5. Browser → Next.js → Images bucket

    in progress · Uploads go through a server action with the upload key.

  6. Browser → Media Worker → Images bucket

    in progress · Views go through the Worker with a read-only key.

  7. GitHub Actions → Postgres

    Every night at 02:30 UTC, pg_dump 17 through the session pooler (IPv4).

  8. GitHub Actions → Backups bucket

    gzip and age, then daily/ (and weekly/ on Sundays) with a write-only key.

  • request or data
  • scheduled
  • in progress, not live
  • in progressdesigned, being built
The forum as it runs today. Dotted paths and hatched boxes are the image pipeline, which is designed and being built; dashed paths run on a schedule; everything solid is live. Vercel and Supabase both sit in London, so every query is a short hop.

An account without a card fails closed

This is the idea the whole setup rests on. A free tier with a card on file can turn into a bill the month a post goes viral or a bot finds your upload form. A free tier with no card can only stop. For a student forum, a few hours of broken images is a much better failure than an invoice nobody budgeted for.

We signed up for Vercel, Supabase, GitHub, Backblaze and Cloudflare without entering a card. Backblaze is the most explicit about it: with no payment method on the account, it cannot bill, and going past the free 10 GB would need a card plus Backblaze's daily spending caps. The other official pages mostly don't say whether a card is needed at sign-up, so take this as our experience, not a guarantee.

That's also why files live on Backblaze. Cloudflare R2 has a 10 GB free tier too, but we wanted an account with no card at all, and Backblaze spelled out how that works. The limits follow the same pattern. On Vercel Hobby, going over a limit pauses that feature rather than billing. On the free Workers plan, requests past the daily limit fail instead. You accept an outage as the worst case.

Every free tier has a catch

Vercel Hobby is for personal, non-commercial use only. Ads, paid hosting or being paid to build the site count as commercial; donations don't. Inside that, you get 100 GB of Fast Data Transfer and a million function invocations a month.

Supabase Free gives you two active projects, a 500 MB database, 50,000 monthly active users and 5 GB of egress. It also pauses a project after a week without activity, and it takes no automatic backups. So we do both ourselves. One GitHub Actions job reads a single row every three days to keep the project awake. Another dumps the data every night at 02:30 UTC, encrypts it, and uploads it to Backblaze with a key that can write backups but can't read or delete them. There's a newer catch too: since September 2026 Supabase meters log ingest and log queries. It isn't enforced until early 2027, but our org once showed about 144 GB of log queries in a single day without us doing anything unusual. Worth watching now.

Supabase's built-in mailer only allows a few emails an hour, which isn't enough for magic links. Gmail SMTP needs 2-step verification and an app password, and allows roughly 500 emails a day for a normal account. That number comes from third parties, because Google doesn't publish consumer limits clearly. At our scale it's plenty, and Resend's free plan is the fallback.

Cloudflare Workers Free stops at 100,000 requests a day, resetting at 00:00 UTC, with 10 ms of CPU per request. And Backblaze B2 gives the first 10 GB of storage free, shared by everything in the account. For us that means images and backups draw from the same 10 GB. Egress is free up to three times your average monthly storage, and free to Cloudflare. The storage side has its own write-up: free image hosting with Backblaze B2 behind a Cloudflare Worker.

A few habits keep you inside the limits

Cache public pages. Ours read through a cookieless Supabase client inside Next's "use cache", so one cached result serves every visitor instead of each visit running its own function and query.

Pin functions next to the database. Supabase runs in London (eu-west-2), so the Vercel functions run in London too. Every query is a short hop instead of a trip across Europe. It's one line:

{"regions":["lhr1"]}
vercel.json

Compress uploads in the browser, before they cost anything. In the image design, files get re-encoded to WebP, with a JPEG fallback because Safari can't encode WebP, to at most 1,600 px on the longest side and 1 MB after compression. Re-encoding drops EXIF and location data as a bonus.

Put hard caps in the database, where a bug in the frontend can't skip them. For images, Postgres triggers allow 3 images per thread, none in comments, 15 per member per day and 300 site-wide per day, and stop uploads at 8 GB in total. That leaves room for backups in the shared 10 GB.

I'd start paying when a limit stops being hypothetical

The triggers are concrete. If the forum ever makes money from ads or paid hosting, Vercel Hobby no longer fits. If images and backups head past 10 GB, the 8 GB stop kicks in first; beyond that the honest fix is a card on Backblaze with its daily spending caps set, not a cleverer cap. If the database nears 500 MB, or Supabase's log metering starts counting against us in 2027, that's the Supabase bill. If the Worker regularly hits 100,000 requests a day, images break until midnight UTC, and that's the signal for Cloudflare. Email is the one limit with a free way out: Resend's free plan comes before anything paid.

Until one of them happens, the only line in the budget is the domain.

If you're starting one tomorrow

Sign up without a card and read each provider's limits page before you rely on it; GitHub's Actions billing page is the one that confirms public repos run free on standard runners. Add the keep-awake job and the nightly dump on day one, not after the first pause. Write the caps into the database. And decide in advance which limit you'd pay to lift first, so the day it happens is a decision instead of a surprise. The workflows are all in the public repo.