Supabase CLI and GitHub Actions: Consistent Schema Migration Handling
0 reputation · 25 Nov 2025, 14:52 UTC
0 reputation · 25 Nov 2025, 14:52 UTC
Goal: achieve identical schema migration outcomes when running Supabase CLI locally via supabase start and in a CI pipeline that uses supabase db push against a temporary project.
Constraints: the CLI does not automatically remove ephemeral Supabase projects created for CI, requiring manual cleanup to avoid quota limits, and the Docker images pulled by supabase start may differ from those used in the CI runner, potentially leading to mismatched Postgres extensions or behavior.
Questions: How can teams ensure the Docker image versions used by supabase start match those used in CI runners? What mechanisms exist for automatically cleaning up temporary Supabase projects after CI jobs finish? Is it possible to pin the exact Docker image versions within the Supabase CLI configuration to prevent drift?
34775 reputation · 25 Nov 2025, 23:02 UTC
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.
supabase/docker unless overridden.supabase init --docker-image supabase/docker:1.0.0
# or edit supabase.toml
# docker-image = "supabase/docker:1.0.0"
supabase start
# then
docker images | grep supabase/docker
# should show tag 1.0.0
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
PROJECT_ID=$(supabase projects create --name "ci-${{ github.sha }}" --plan free --output json | jq -r .id)
# store PROJECT_ID for later
SUPABASE_URL and SUPABASE_ANON_KEY environment variables.supabase projects delete --id $PROJECT_ID --force
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.
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)?
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 25 Nov 2025, 18:20 UTC
Locking supabase/cli@v1.2.3 guarantees the CLI will pull supabase/supabase:1.2.3, but the same tag can point to a newer digest if the image is rebuilt. For true reproducibility, verify the digest after the pull.
# after supabase start
docker images --digests | grep supabase/supabase
# compare the DIGEST column with the one you expect (e.g., sha256:abcd…)
supabase start --docker-image supabase/supabase@sha256:abcd1234
Using a digest in the --docker-image flag ensures the exact image is used, even if the tag later moves. Combine this with the SUPABASE_CLI_IMAGE env var in GitHub Actions for a fully locked pipeline.