CI/CD integration
revector is a single static binary that reads its config from flags or
REVECTOR_* environment variables and runs fully non-interactively — which is
exactly what a pipeline needs. The natural split is:
- On every pull request — run
revector validate(offline, no Qdrant) so a broken or unorderable chain never merges. Optionally addrevector diffas a drift guard. - On deploy / merge to
main— runrevector upagainst the target Qdrant so the schema moves forward in lockstep with the code that depends on it.
The two safety nets that make this trustworthy in automation are built in: the SHA-256 checksum guard refuses to proceed if an already-applied migration file was edited, and the advisory lock (held as a point in the tracking collection) stops two concurrent pipeline runs from applying at once. Neither needs configuration.
Non-interactive usage
Three things matter when running outside a TTY:
-
Pass connection details as env vars, not flags, so secrets stay out of process listings and logs:
export REVECTOR_URL="$QDRANT_URL" export REVECTOR_API_KEY="$QDRANT_API_KEY" # from your CI secret store -
Use
-y/--yesfor anything that prompts.upis non-destructive and runs unattended, butdownandto(when rolling back) require confirmation in an interactive shell —-yis mandatory for them in CI. -
Rely on exit codes. Every command exits non-zero on failure, so no extra
grep-the-output logic is needed.revector diffexits non-zero when it finds drift;validateexits non-zero on a malformed or unresolvable chain.
Installing the binary in a runner
Use the prebuilt installer — no Rust toolchain required:
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/diegoglozano/revector/releases/latest/download/revector-installer.sh | sh
Pin to a specific release in CI rather than tracking latest, so a new release
can't change behavior under you — swap latest/download for
download/vX.Y.Z. (See Security & supply chain for
verifying release artifacts.)
GitHub Actions
Validate on every pull request
This job needs no Qdrant and no secrets — it just parses the migration files and resolves the chain offline. Keep it fast and required.
# .github/workflows/migrations.yml
name: migrations
on:
pull_request:
paths:
- "migrations/**"
- "revector.toml"
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install revector
run: |
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/diegoglozano/revector/releases/latest/download/revector-installer.sh | sh
- name: Validate migration chain
run: revector validate
Apply on deploy
Gate this on your deploy event (a push to main, a tag, or an environment
deployment) and pull the Qdrant URL and API key from repository or environment
secrets. The GitHub environment: key lets you require a manual approval before
the migration runs.
apply:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production # optional: gate behind a required reviewer
env:
REVECTOR_URL: ${{ secrets.QDRANT_URL }}
REVECTOR_API_KEY: ${{ secrets.QDRANT_API_KEY }}
steps:
- uses: actions/checkout@v4
- name: Install revector
run: |
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/diegoglozano/revector/releases/latest/download/revector-installer.sh | sh
- name: Show plan
run: revector status
- name: Apply pending migrations
run: revector up
revector up is idempotent: every operation checks existence before
create/delete, so a re-run after a partial failure (or a duplicate pipeline
trigger) is safe. A run with nothing pending is a no-op that exits zero.
Preview the plan on the PR
To see what a merge would change before it merges, run up --dry-run against
a staging instance — it prints the ordered plan without touching anything:
- name: Plan against staging
env:
REVECTOR_URL: ${{ secrets.STAGING_QDRANT_URL }}
REVECTOR_API_KEY: ${{ secrets.STAGING_QDRANT_API_KEY }}
run: revector up --dry-run
Drift detection as a guard
If you want CI to catch a live collection that has drifted from its declared
spec (someone hand-edited config in the Qdrant dashboard, say), add a
diff step. It exits non-zero on any difference, so a failing job
flags the drift:
- name: Check for drift
run: revector diff products --spec specs/products.spec.yaml
This is declaration-driven — only fields you actually wrote in the spec are compared — so it won't false-positive on Qdrant's read-time defaulting. See the drift detection guide for the spec-file shape.
GitLab CI
The same shape maps onto any runner. Store QDRANT_URL and QDRANT_API_KEY as
masked/protected CI/CD variables.
stages: [validate, deploy]
validate-migrations:
stage: validate
image: debian:stable-slim
before_script:
- apt-get update && apt-get install -y curl
- curl --proto '=https' --tlsv1.2 -LsSf
https://github.com/diegoglozano/revector/releases/latest/download/revector-installer.sh | sh
- export PATH="$HOME/.cargo/bin:$PATH"
script:
- revector validate
apply-migrations:
stage: deploy
image: debian:stable-slim
rules:
- if: $CI_COMMIT_BRANCH == "main"
variables:
REVECTOR_URL: $QDRANT_URL
REVECTOR_API_KEY: $QDRANT_API_KEY
before_script:
- apt-get update && apt-get install -y curl
- curl --proto '=https' --tlsv1.2 -LsSf
https://github.com/diegoglozano/revector/releases/latest/download/revector-installer.sh | sh
- export PATH="$HOME/.cargo/bin:$PATH"
script:
- revector status
- revector up
Rollbacks in automation
Rollbacks are deliberately less automatic, because a down can be destructive
or irreversible (revector refuses to auto-invert a step that needs unrecorded
prior state — see Migration files). If you do wire a
rollback step — for example a manually-triggered job — it must pass -y and
should target an explicit revision rather than relying on step counts:
- name: Roll back to a known-good revision
run: revector to 0002_index_and_quantize -y
Prefer revector to <rev> -y over down --steps N in pipelines: it's explicit
about the end state and idempotent if re-run.
Checklist
-
revector validateruns on every PR that touchesmigrations/. -
Secrets come from the CI secret store as
REVECTOR_API_KEY/REVECTOR_URL, never committed torevector.toml. - The apply job is gated on a deploy event and, ideally, a required reviewer / protected environment.
-
revector status(orup --dry-run) runs beforeupso the plan is in the logs. -
The installer is pinned to a release tag, not
latest. -
Any rollback job passes
-yand targets an explicit revision.