This guide explains how to set up a cloud-hosted PostgreSQL database for the scheduled pipeline to run via GitHub Actions.
| Provider | Free Tier | Best For |
|---|---|---|
| Supabase | 500MB, 2 projects | Easy setup, great UI |
| Neon | 512MB, unlimited projects | Serverless, auto-scaling |
| Railway | $5/month credit | Simple deployment |
| Render | 90 days free | Full PaaS solution |
- Go to supabase.com and sign up
- Create a new project
- Choose a region close to GitHub's servers (US East recommended)
- Set a secure database password
- Go to Settings > Database
- Under Connection string, copy the URI format:
postgresql://postgres:[YOUR-PASSWORD]@db.[PROJECT-REF].supabase.co:5432/postgres
For GitHub Actions, use the Session pooler connection (port 5432) to avoid connection timeouts:
postgresql://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@aws-0-us-east-1.pooler.supabase.com:5432/postgres
- Go to neon.tech and sign up
- Create a new project
- Create a database named
leaderboard
- Go to Dashboard > Connection Details
- Copy the connection string:
postgresql://[user]:[password]@[host]/leaderboard?sslmode=require
Add these secrets to your repository:
- Go to Settings > Secrets and variables > Actions
- Add the following secrets:
| Secret Name | Description |
|---|---|
DATABASE_URL |
PostgreSQL connection string from cloud provider |
REDIS_URL |
Redis URL (optional for GitHub Actions - can omit) |
BIGQUERY_PROJECT |
Your Google Cloud project ID |
BIGQUERY_CREDENTIALS |
Full JSON content of service account key |
GH_PAT |
GitHub Personal Access Token (for API calls) |
# Supabase (pooled)
postgresql://postgres.[ref]:[password]@aws-0-us-east-1.pooler.supabase.com:5432/postgres
# Neon
postgresql://[user]:[password]@[endpoint].neon.tech/leaderboard?sslmode=require
# Railway
postgresql://[user]:[password]@[host].railway.app:5432/railway
After setting up the cloud database, run the initialization:
# Set the cloud DATABASE_URL locally
export DATABASE_URL="postgresql://..."
# Run init script
python scripts/init_db.pyRun the workflow manually:
- Go to Actions > Scheduled Pipeline
- Click Run workflow
- Select
full-pipelineaction
The pipeline will create tables if they don't exist.
import asyncio
from src.db.database import create_worker_session_maker
async def test():
async with create_worker_session_maker()() as db:
result = await db.execute("SELECT 1")
print("Connection successful!")
asyncio.run(test())Run a dry-run of the pipeline:
- Go to Actions > Scheduled Pipeline
- Click Run workflow
- Set
dry_runtotrue - Check the logs for connection success
If you have existing local data to migrate:
# Export from local PostgreSQL
pg_dump -h localhost -p 5433 -U postgres -d leaderboard > backup.sql
# Import to cloud (modify connection details)
psql "postgresql://user:pass@cloud-host/database" < backup.sql| Provider | Free Limit | When to Upgrade |
|---|---|---|
| Supabase | 500MB | ~50k contributors |
| Neon | 512MB | ~50k contributors |
| Railway | $5/mo credit | Heavy usage |
Current database size estimate:
- ~1KB per contributor (enriched)
- ~82k contributors = ~80MB
- Well within free tier limits
- Use pooled connections (Supabase:
pooler.supabase.com) - Set
statement_timeoutin DATABASE_URL:?statement_timeout=60000
Most cloud providers require SSL:
?sslmode=require
Ensure database user has:
- CREATE TABLE
- SELECT, INSERT, UPDATE, DELETE
- USAGE on schema
- Never commit credentials - Use GitHub Secrets only
- Use service accounts - Don't use personal credentials
- Restrict IP access - If possible, allow only GitHub Actions IPs
- Rotate secrets - Change passwords periodically
- Monitor usage - Set up alerts for unusual activity