# Why Supabase pauses free projects, and three ways to stop it

> What Supabase's docs actually say about the 7-day pause, how to restore a paused project, and three fixes: a free GitHub Action, the Pro plan, or a backend that scales to zero instead of pausing.

Source: https://scribase.com/blog/why-supabase-pauses-free-projects-and-three-ways-to-stop-it

By Scribase, 2026-11-12.

If you landed here, your Supabase project probably answered every request with
a bare "Failed to fetch" one morning, and the dashboard showed a **Restore
project** button where your app used to be. This post explains why that
happens, quoting the documentation rather than folklore, and gives three ways
to make it not happen again. The first one is free and takes one file.

## What the docs say

Supabase's pricing page states it plainly: "Free projects are paused after 1
week of inactivity", and the Free plan has a "Limit of 2 active projects"
([pricing](https://supabase.com/pricing)). The production checklist adds the
nuance: "We may pause applications on the Free Plan that exhibit low activity
in a 7-day period to save on server resources"
([going into production](https://supabase.com/docs/guides/platform/going-into-prod)).

What counts as activity, per the official FAQ: "Opening the project in the
dashboard or sending real requests from your app both count as activity", and
"You get an email about a week before a pause, and another once it happens"
([FAQ](https://supabase.com/kb/faqs/platform/free-project-pausing)).
Supabase does not publish the exact threshold. Requests through the project's
API that touch the database are the documented path, which matters for the
fix below.

Paid plans are not paused for inactivity: "Upgrade to Pro to guarantee that
we won't pause your project for inactivity" (same production checklist).

## How to tell it is paused, and how to get it back

A paused project answers every API request with HTTP **540**
([HTTP status codes](https://supabase.com/docs/guides/platform/http-status-codes)).
In a browser the symptom is usually a network error without CORS headers, so
the app reports "Failed to fetch" or "Load failed" rather than 540.

```sh
curl -s -o /dev/null -w '%{http_code}\n' \
  -H "apikey: $SUPABASE_ANON_KEY" "https://YOUR-REF.supabase.co/rest/v1/"
# 200 = awake, 540 = paused
```

To restore: open the project in the dashboard and click **Restore project**.
You need a free slot (2 active projects on the Free plan; paused projects do
not count). The docs say "users have a 1-year window to restore the project
on the platform from within Supabase Studio", after which the backup file and
Storage objects can still be downloaded
([upgrading](https://supabase.com/docs/guides/platform/upgrading)). You may
read elsewhere that paused projects are deleted after 90 days; as of
2026-11-12 the docs say one year for one-click restore. Check the current
docs before relying on either number, and take a `supabase db dump` as soon
as the project is back.

## Fix 1: a daily query from a free GitHub Action

The documented path to "active" is real database requests through the API.
So make one every day. A scheduled GitHub Actions workflow with one `curl`
is enough (no third-party action, no runtime to update):

```yaml
# .github/workflows/keep-alive.yml  (secrets: SUPABASE_URL, SUPABASE_ANON_KEY)
name: Keep Supabase alive
on:
  schedule:
    - cron: "17 6 * * *"
  workflow_dispatch:
permissions:
  contents: read
jobs:
  ping:
    runs-on: ubuntu-latest
    steps:
      - name: Read one row   # any small table works
        run: |
          curl -fsS --retry 3 --retry-delay 10 \
            "${{ secrets.SUPABASE_URL }}/rest/v1/keepalive?select=*&limit=1" \
            -H "apikey: ${{ secrets.SUPABASE_ANON_KEY }}" \
            -H "Authorization: Bearer ${{ secrets.SUPABASE_ANON_KEY }}"
```

Two details matter more than the cron line:

- **Read a table, not just the root.** A `GET /rest/v1/` alone proves the
  gateway is up; reading one row of a small table is a database request. The
  step above does that with the anon key, so the table needs RLS on and a
  policy that allows the read (a `keepalive` table with one public row is the
  usual shape). An RPC that returns a constant has been reported as not
  enough; a read that touches a table is the safe choice.
- **Watch the watcher.** GitHub disables scheduled workflows in repositories
  with no pushes for 60 days, and a weekly cron can miss the 7-day window
  after one failed run. Turn on failure
  notifications for the workflow so a silent stop does not go unnoticed.

The same idea works from Vercel cron, a Cloudflare Worker cron trigger, or
any machine with `curl`; GitHub Actions is just a free scheduler for it. Treat every keep-alive as fragile by construction: Supabase decides
what counts as activity, and the docs say "may pause".

## Fix 2: pay Supabase

Supabase's Pro plan costs $25 a month plus $10 a month of compute credits per
organization ([pricing](https://supabase.com/pricing)), and it is the only option that
Supabase itself documents as removing the pause. If the project earns money
or holds data you cannot lose, this is the straightforward answer and there
is nothing clever to add.

## Fix 3: a backend that scales to zero instead of pausing

The pause exists because a free project occupies a running Postgres whether
or not anyone is using it. The other way to solve that is a backend where
an idle project costs nothing to keep and wakes on the next request.

If you need Postgres only, Neon's free plan scales compute to zero after
five minutes idle and reactivates on the next query
([Neon: scale to zero](https://neon.com/docs/introduction/scale-to-zero));
you keep the database and bring your own auth, storage and email.

If you need the whole backend your app already uses (auth, storage,
realtime, functions, the supabase-js client), that is what
[Scribase](https://scribase.com/supabase-project-paused) is for: one project
with Postgres, Auth, Storage, Realtime and Edge Functions behind one URL and
one anon key, plus a Resend-compatible email API from the same vendor. Idle
projects scale to zero on every tier and are never paused; there is no cap on
the number of projects. One project is free with no time limit (0.5 GB
database, 1 GB files, no card); new accounts start with 14 days of Hobby, and
more projects are from $5 a project a month. Moving a project is one importer run (schema, data, RLS
policies, auth users with their password hashes, storage objects, with row
counts per table at the end), and export is a button, so you can leave the
same way. If a paused project is still inside its restore window, the
[rescue tool](https://scribase.com/supabase-project-paused#scribase) runs
that import into a free 72-hour project with no account.

Two defaults come with that move and are worth naming, because they are the
reason to centralize rather than just to stop the pause: the project does
not go to sleep when nobody is looking, and a migration that would leave a
public table without row level security is refused before it runs
([how that works](https://scribase.com/security)).

## Which one

- Side project you want to keep free: Fix 1, today, and set a calendar
  reminder to check the Action's last run.
- Production on Supabase: Fix 2.
- Four vendors, four invoices, and a pause on top: Fix 3, and bring the
  email and auth with you.

Sources, each read on 2026-11-12: Supabase
[pricing](https://supabase.com/pricing),
[going into production](https://supabase.com/docs/guides/platform/going-into-prod),
[free project pausing FAQ](https://supabase.com/kb/faqs/platform/free-project-pausing),
[HTTP status codes](https://supabase.com/docs/guides/platform/http-status-codes),
[upgrading](https://supabase.com/docs/guides/platform/upgrading); Neon
[scale to zero](https://neon.com/docs/introduction/scale-to-zero); Scribase
[pricing](https://scribase.com/pricing).