Answer the core question
1. Pin the Docker image used by the CLI – set SUPABASE_DOCKER_IMAGE or docker-image in supabase.toml to the exact tag you run locally.
2. Ensure the CI runner pulls the same tag – export the same environment variable before any supabase command.
3. Automate project cleanup – run supabase projects delete --id --force (or by name) in a final step of the workflow.
Why this works
- The CLI always pulls the image named
supabase/docker unless overridden.
- Using a fixed tag removes the “latest” drift that can change extensions or Postgres behavior between runs.
- Deleting the temporary project after the job guarantees you won’t hit the project‑quota limit.
Concrete steps for your repository
- Pin locally
supabase init --docker-image supabase/docker:1.0.0
# or edit supabase.toml
# docker-image = "supabase/docker:1.0.0"
- Verify locally
supabase start
# then
docker images | grep supabase/docker
# should show tag 1.0.0
- Configure GitHub Actions
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set Docker image
run: echo "SUPABASE_DOCKER_IMAGE=supabase/docker:1.0.0" >> $GITHUB_ENV
- name: Install Supabase CLI
run: curl -fsSL https://supabase.com/docs/cli/install.sh | sh
- name: Run migrations
run: supabase db push
- Create a temporary project in the workflow
PROJECT_ID=$(supabase projects create --name "ci-${{ github.sha }}" --plan free --output json | jq -r .id)
# store PROJECT_ID for later
- Run your tests against $PROJECT_ID – supply the project ID via
SUPABASE_URL and SUPABASE_ANON_KEY environment variables.
- Cleanup
supabase projects delete --id $PROJECT_ID --force
- Optional: confirm deletion
supabase projects list | grep $PROJECT_ID || echo "Project removed"
These steps guarantee that the Docker image version used in local supabase start and CI supabase db push is identical, and that any temporary projects are removed automatically after the job.
Missing diagnostic detail
To fine‑tune the cleanup logic, could you confirm whether your CI workflow creates projects by name or id, and if you prefer a naming convention (e.g., suffixing with -ci)?