If you’re using Supabase’s generous free tier for side projects, you’ve probably seen the dreaded email: your project will be paused due to inactivity. The rule is simple—if no API requests hit your database for 7 days, Supabase assumes the project is abandoned and pauses it to save resources. No amount of dashboard browsing counts. You need actual REST API calls.
The fix? A tiny scheduled task that pings your database a couple of times a week. You could spin up a server, use an external cron service, or—my favorite—just use GitHub Actions. You already have a repo (or can create one in 30 seconds), and it’s completely free for public repositories (and even private repos get generous free minutes).
Here’s exactly how to set up a “keep alive” cron with GitHub Actions, step by step.
What You’ll Need
- A Supabase project on the free plan
- A GitHub account
- 5 minutes
Step 1: Get Your Supabase Credentials
From your Supabase dashboard, go to Project Settings → API. Copy two values:
-
Project URL(e.g.,https://abcxyz.supabase.co) -
anonpublic key (starts witheyJ...)
We’ll use the anon key because we only need to read one row from a table. Never use the service_role key here—it has full admin rights and should stay secret.
Step 2: Create (or Reuse) a GitHub Repository
You can add the workflow to an existing project repo, or create a brand-new one just for this task. Even an empty repository works fine.
Step 3: Store Your Supabase Credentials as Secrets
We don’t hardcode keys. Instead, we’ll add them to GitHub so the workflow can access them safely.
Go to your repo on GitHub → Settings → Secrets and variables → Actions.
Click New repository secret and add:
-
Name:
SUPABASE_URL -
Value:
https://abcxyz.supabase.coClick **Add secret, then repeat for the second secret:**
Name:
SUPABASE_KEYValue: your anon key
You should now see both listed under “Repository secrets”.
Step 4: Create the Workflow File
In your repository, create a file at exactly:
.github/workflows/keep_alive.yml
text
Paste this YAML:
name: Keep Supabase Alive
on:
schedule:
# Runs every day at midnight UTC
- cron: '0 0 * * *'
workflow_dispatch: # allows manual triggering from the Actions tab
jobs:
ping:
runs-on: ubuntu-latest
steps:
- name: Ping Supabase Database
run: |
curl -X GET "${{ secrets.SUPABASE_URL }}/rest/v1/your_table_name?select=id&limit=1" \
-H "apikey: ${{ secrets.SUPABASE_KEY }}" \
-H "Authorization: Bearer ${{ secrets.SUPABASE_KEY }}"
Enter fullscreen mode Exit fullscreen mode
Important: Replace your_table_name with the actual name of a table in your Supabase database. The table must have an id column (or adjust the select parameter).
The schedule 0 0 * * * means midnight UTC daily—well within the 7-day limit. Even twice a week (0 0 * * 0,5 for Sunday and Friday) is enough, but daily is harmless and easy to remember.
The workflow_dispatch line lets you run the job manually to test it, which we’ll do next.
Step 5: Check Row Level Security (RLS)
By default, Supabase enables Row Level Security on new tables. The anon key will only succeed if there’s a policy that allows SELECT for the public role (or anon). If the table is empty or RLS is blocking reads, the curl will fail with a 401 or 403.
Quick check in Supabase SQL Editor:
-- Check if RLS is enabled on your table
SELECT relname, relrowsecurity
FROM pg_class
WHERE relname = 'your_table_name';
-- See which policies exist for that table
SELECT polname, polcmd, roles
FROM pg_policy
WHERE polrelid = 'your_table_name'::regclass;
Enter fullscreen mode Exit fullscreen mode
roles showing {0} means “public” (which includes the anon key).
polcmd = ‘r’ means SELECT.
If you see no policy and RLS is true, create one:
CREATE POLICY "Allow public read"
ON your_table_name
FOR SELECT
TO anon
USING (true);
Enter fullscreen mode Exit fullscreen mode
Now the anon key can read rows from that table.
Step 6: Test the Workflow Manually
Don’t wait for the cron to fire—test it now.
Go to your repo → Actions tab.
Click Keep Supabase Alive in the left sidebar.
Click the Run workflow button → Run workflow.
A new run will appear in a few seconds. Click on it, then click the ping job, and expand the Ping Supabase Database step. If you see a JSON response (even []) without errors, it’s working.
You can also verify in Supabase under Logs & Analytics by running:
SELECT timestamp, event_message
FROM edge_logs
ORDER BY timestamp DESC
LIMIT 5;
Enter fullscreen mode Exit fullscreen mode
You should see a REST request matching the time of your test.
What You’ve Achieved
You now have a cost-free, zero-maintenance heartbeat for your Supabase project. Every day (or however you set the cron) GitHub Actions will ping your database with a harmless SELECT, resetting the inactivity timer.
A few notes to keep things clean:
Don’t hammer the endpoint; one request per day is plenty.
This approach has kept my side projects alive for months without a single pause email. Hopefully it does the same for yours.
Got questions or a different method you use? Drop a comment!
답글 남기기