A GitHub Action that detects differences between Supabase environments and reports them as Pull Request comments.
Supports 2-environment (dev/prd) or 3-environment (dev/stg/prd) comparison.
Catch deployment discrepancies and environment inconsistencies early to maintain production stability.
- Edge Functions - Detect existence and version differences
- RLS Policies - Detect Row Level Security policy definition differences
- SQL Functions - Detect PostgreSQL function definition differences
- Schemas - Detect table structure differences (columns, indexes, constraints)
- Multi-environment support - Compare dev→prd or dev→stg→prd
- Post readable Markdown-formatted comments to Pull Requests
- Option to fail CI when differences are detected
Edge Functions comparison is limited to metadata only (name, version, status). The Supabase Management API does not expose the function source code, so we cannot compare the actual implementation.
| What we can compare | What we cannot compare |
|---|---|
| Function existence | Source code |
| Version number | Function logic |
| Status | Dependencies |
Note: Different version numbers indicate different deployment counts, not necessarily different code. If you need source code comparison, manage your Edge Functions in your Git repository and use standard diff tools.
In your repository's Settings > Secrets and variables > Actions, add:
| Secret Name | Description | How to Get |
|---|---|---|
SUPABASE_ACCESS_TOKEN |
Management API token | Supabase Dashboard |
SUPABASE_DEV_PROJECT_REF |
Dev environment project ref | Project Settings > General |
SUPABASE_DEV_DB_URL |
Dev environment DB connection URL | See Database URL Format below |
SUPABASE_STG_PROJECT_REF |
Staging environment project ref (optional) | Project Settings > General |
SUPABASE_STG_DB_URL |
Staging environment DB connection URL (optional) | See Database URL Format below |
SUPABASE_PRD_PROJECT_REF |
Prod environment project ref | Project Settings > General |
SUPABASE_PRD_DB_URL |
Prod environment DB connection URL | See Database URL Format below |
Note: If you provide both
stg_project_refandstg_db_url, the action will compare dev→stg and stg→prd. Otherwise, it compares dev→prd directly.
⚠️ Important: You must use the Session Pooler connection URL. The legacydb.[project-ref].supabase.coformat is deprecated and will not work.
How to get the correct URL:
- Go to your Supabase project dashboard
- Click the "Connect" button (green button in the top right)
- Select "Session Pooler" (port 5432)
- Copy the connection string
Correct format:
postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:5432/postgres
Example:
postgresql://postgres.abcdefghijklmnop:[email protected]:5432/postgres
Why Session Pooler?
- GitHub Actions runners only support IPv4 connections
- Session Pooler is IPv4 compatible, while Transaction Pooler requires an IPv4 add-on
- Session Pooler supports PREPARE statements (required by some PostgreSQL clients)
- The legacy direct connection (
db.[ref].supabase.co) may not resolve
| Connection Type | Port | IPv4 | PREPARE | Recommendation |
|---|---|---|---|---|
| Session Pooler | 5432 | ✅ Compatible | ✅ Supported | ✅ Recommended |
| Transaction Pooler | 6543 | ❌ Requires add-on | ❌ Not supported | Not recommended |
| Direct Connection | 5432 | ❌ May not resolve | ✅ Supported | Local development only |
.github/workflows/supabase-diff.yml:
name: Supabase Diff Check
on:
pull_request:
branches: [main]
jobs:
diff-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: anies1212/supabase-diff-action@v1
with:
supabase_access_token: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
dev_project_ref: ${{ secrets.SUPABASE_DEV_PROJECT_REF }}
dev_db_url: ${{ secrets.SUPABASE_DEV_DB_URL }}
prd_project_ref: ${{ secrets.SUPABASE_PRD_PROJECT_REF }}
prd_db_url: ${{ secrets.SUPABASE_PRD_DB_URL }}
github_token: ${{ secrets.GITHUB_TOKEN }}| Input | Description |
|---|---|
supabase_access_token |
Supabase Management API access token |
dev_project_ref |
Dev environment project reference |
dev_db_url |
Dev environment PostgreSQL connection URL |
prd_project_ref |
Prod environment project reference |
prd_db_url |
Prod environment PostgreSQL connection URL |
github_token |
GitHub Token (for PR comments) |
| Input | Default | Description |
|---|---|---|
stg_project_ref |
- | Staging environment project reference |
stg_db_url |
- | Staging environment PostgreSQL connection URL |
check_edge_functions |
true |
Check Edge Functions |
check_rls_policies |
true |
Check RLS Policies |
check_sql_functions |
true |
Check SQL Functions |
check_schemas |
true |
Check Schemas |
fail_on_diff |
false |
Fail the action if differences are found |
excluded_schemas |
(※1) | Comma-separated list of schemas to exclude |
※1: Default excluded schemas: pg_catalog, information_schema, extensions, pg_toast, pgsodium, vault, graphql, graphql_public
| Output | Description |
|---|---|
has_diff |
Whether differences were found (true/false) |
diff_summary |
Diff summary (JSON) |
edge_functions_diff |
Edge Functions diff (JSON) |
rls_policies_diff |
RLS Policies diff (JSON) |
sql_functions_diff |
SQL Functions diff (JSON) |
schemas_diff |
Schemas diff (JSON) |
- uses: anies1212/supabase-diff-action@v1
id: diff
with:
# ... inputs
- name: Handle differences
if: steps.diff.outputs.has_diff == 'true'
run: echo "Differences found between environments"When differences are detected, a comment like this is posted to the PR:
Differences detected between dev and prod environments.
| Function | dev | prod | Status |
|---|---|---|---|
| send-email | v3 | v2 | version: 3 → 2 |
| new-feature | v1 | - | Only in dev |
| Table | Policy | dev | prod | Status |
|---|---|---|---|---|
| public.users | select_own | ✓ | ✓ | qual: definition differs |
| Schema | Function | dev | prod | Status |
|---|---|---|---|---|
| public | calculate_total(integer) | ✓ | ✓ | definition: differs |
| Schema | Table | dev | prod | Status |
|---|---|---|---|---|
| public | orders | ✓ | ✓ | Has differences |
Diff Details
- column "discount" data_type: numeric → integer
- index "orders_user_id_idx": only in dev
- uses: anies1212/supabase-diff-action@v1
with:
supabase_access_token: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
dev_project_ref: ${{ secrets.SUPABASE_DEV_PROJECT_REF }}
dev_db_url: ${{ secrets.SUPABASE_DEV_DB_URL }}
stg_project_ref: ${{ secrets.SUPABASE_STG_PROJECT_REF }}
stg_db_url: ${{ secrets.SUPABASE_STG_DB_URL }}
prd_project_ref: ${{ secrets.SUPABASE_PRD_PROJECT_REF }}
prd_db_url: ${{ secrets.SUPABASE_PRD_DB_URL }}
github_token: ${{ secrets.GITHUB_TOKEN }}When staging environment is configured, the action compares:
- Dev → Stg: Detect items only in dev, only in stg, or different between dev and stg
- Stg → Prd: Detect items only in stg, only in prd, or different between stg and prd
- uses: anies1212/supabase-diff-action@v1
with:
# ... required inputs
check_edge_functions: 'true'
check_rls_policies: 'true'
check_sql_functions: 'false' # Skip SQL Functions
check_schemas: 'false' # Skip Schemas- uses: anies1212/supabase-diff-action@v1
with:
# ... required inputs
fail_on_diff: 'true'- uses: anies1212/supabase-diff-action@v1
with:
# ... required inputs
excluded_schemas: 'pg_catalog,information_schema,extensions,my_internal_schema'- Node.js 20.x
- npm
# Clone the repository
git clone https://github.com/anies1212/supabase-diff-action.git
cd supabase-diff-action
# Install dependencies
npm install
# Build
npm run build
# Type check
npm run typecheck
# Test
npm run testsupabase-diff-action/
├── action.yml # GitHub Action definition
├── src/
│ ├── index.ts # Entry point
│ ├── types.ts # Type definitions
│ ├── supabase/
│ │ ├── functions.ts # Edge Functions fetcher
│ │ ├── rls.ts # RLS Policies fetcher
│ │ ├── sql-functions.ts # SQL Functions fetcher
│ │ └── schemas.ts # Table schemas fetcher
│ ├── diff/
│ │ └── compare.ts # Diff comparison logic
│ └── github/
│ └── comment.ts # PR comment posting
└── dist/ # Built files
Contributions are welcome! See CONTRIBUTING.md for details.
If you discover a security vulnerability, please see SECURITY.md.