Skip to main content

vecshift

Safe, observable embedding migrations for any vector store, with any embedding model.

CI PyPI Python Docker image License: Apache 2.0 Status: alpha


Why

Every team running RAG or semantic search eventually wants a better or cheaper embedding model, different dimensions, new chunking, or a different vector store. Today each of those is a one-off project: a re-embed script, rate-limit workarounds, a new index, a manual cutover, and no real answer to two questions:

  1. Is the new model actually better on our data?
  2. What's actually in our index right now? Which model made these vectors? Is it mixed? Do we still have the text to re-embed it?

VecShift answers those first, then makes the migration itself safe and repeatable.

What it will do

Command Purpose Status
vecshift fingerprint Print a stable tag identifying an embedding configuration's vector space ✅ Available
vecshift doctor Inspect an index: mixed models or sizes, zero and unnormalized vectors, duplicates, missing text, indexing and change-tracking gaps ✅ pgvector and Supabase
vecshift bench Compare embedding models on a sample of your data: recall, latency, cost, storage ✅ Available
vecshift init / plan Write a migration job, then check it and estimate tokens, cost, time, and storage ✅ Available
vecshift apply Re-embed into a side-by-side column with resume, a spend cap, live-write sync, and a concurrent index build ✅ pgvector and Supabase
vecshift eval Compare old and new vectors on your data, per language, with latency vs accuracy, and a go/no-go verdict ✅ pgvector and Supabase
vecshift cutover / rollback Switch searches to the new vectors under the same name, with instant rollback ✅ pgvector and Supabase

Initial targets are pgvector and Qdrant, with an OpenAI-compatible embedding provider (which covers OpenAI, vLLM, Ollama, TEI, and most hosted inference) plus a free mock provider for trying things out.

Design principles

  • Look before you leap. Read-only diagnosis and benchmarking come before any write.
  • Never lose data. Idempotent upserts guarded by updated_at, checkpoints, a dead-letter queue.
  • Know your vector space. Every vector carries a fingerprint of the model configuration that produced it, so mixed or stale vectors are detectable.
  • Data stays home. Runs inside your network. Nothing leaves except to the embedding provider you choose.
  • Free first run. Mock embeddings and a local store, so you can try it without an API key.

Install

Requires Python 3.11 or newer.

pip install vecshift          # or: uv tool install vecshift
vecshift --help

Or run it without installing, with uv or Docker:

uvx vecshift --help
docker run --rm -e VECSHIFT_DSN ghcr.io/osamamu64/vecshift doctor --table public.documents

Try it in two minutes

The demo runs a whole migration on a sample table of English and Arabic articles: check the index, plan, re-embed without locking the table, compare old and new, then switch. It runs offline with vecshift's built-in test model, so there's no API key and nothing leaves your machine.

git clone https://github.com/Osamamu64/vecshift.git
cd vecshift/demo
docker compose up --build --abort-on-container-exit

The reports land in demo/out/. See the demo guide for what each step shows.

Usage

Check an existing pgvector or Supabase index

doctor is read-only and never downloads your vectors, so it's safe against production.

export VECSHIFT_DSN='postgresql://postgres.<project-ref>:<password>@<region>.pooler.supabase.com:5432/postgres'
vecshift doctor --table public.documents

Abridged output:

vecshift doctor · pgvector via Supabase session pooler
Target  public.documents.embedding  vector
Rows    ~1,001 (inspected 1,001, full table)

✖ ERROR    Vectors of different sizes in one index
           Sampled vectors have 2 different sizes: 1536 (901), 3072 (100). They
           come from different models and can't be compared with each other.
✖ ERROR    Vectors from more than one model
           `metadata->>'model'` records 2 different models: text-embedding-ada-002
           (900), text-embedding-3-small (100). ...
⚠ WARNING  No way to track writes during a migration
           There's no logical replication and no updated-at timestamp column, ...
✔ OK       Source text available
           Every sampled row has text in `content`, so the index can be re-embedded.

Add --html report.html for a shareable dashboard of the same results, --json for scripts, or --fail-on error to fail a CI job.

A vecshift doctor HTML report: a verdict banner, key numbers, and findings

The HTML report is a single file that works offline and follows your light or dark theme. It holds statistics only, never vectors or row text, so it's safe to attach to a ticket. See the pgvector and Supabase guide for connection strings, row-level security, and a read-only role recipe.

Find the best embedding model for your data

vecshift bench --docs docs.jsonl \
  -m openai/text-embedding-3-small -m openai/text-embedding-3-large,dims=256 \
  -m ollama/nomic-embed-text --html leaderboard.html

It samples your documents (from a JSONL file or a pgvector table), builds queries with known answers, and ranks each model by retrieval quality, query latency, cost per million documents, and storage. It asks before sending anything to a paid API, and caches embeddings so re-runs are cheap. Run it with no -m for a free, offline first try. See the benchmarking guide.

Plan a migration

vecshift init

At a terminal, init walks you through it: paste your connection string (hidden as you type), pick the vector column and the text it came from, choose the new model, and set a spending limit. It writes a commented vecshift.yaml, can save the connection string to a private .env file if you want it to, and shows the plan. For scripts, pass everything as flags:

vecshift init --table public.documents --model openai/text-embedding-3-large,dims=1024
vecshift plan

plan checks the job against the database without changing anything: the SQL it would run, rows, tokens, cost, duration, and storage, plus anything that would make the migration fail.

Run it

vecshift apply

apply adds the new column next to the old one, embeds every row, and builds the index concurrently, while your application keeps reading and writing. It stops cleanly on Ctrl-C, at your budget, or part way with --until 50, and running it again resumes.

vecshift status            # where it stands, and what to run next
vecshift eval              # better on your data, and how fast? GO / NO-GO
vecshift cutover --check   # safe to switch?
vecshift cutover           # searches use the new vectors, under the same column name
vecshift rollback          # undo, instantly

Your application's SQL doesn't change: cutover gives the new vectors the column name it already uses, in one transaction. Switch the model your app embeds queries with at the same time. See Running a migration and Evaluating a migration.

Tested at scale

The full workflow has been run on a 2-million-row table (PostgreSQL 17, 4 vCPUs, 15 GB of RAM) while an application kept updating and inserting rows about 14 times a second:

Step Time Application writes meanwhile
apply: embed 2 million rows depends on your embedding model and its rate limits 60K+ writes, p99 36 ms, no errors
apply: catch up and build the HNSW index 4.6 min p99 33 ms, no errors
cutover, including rows changed during the run 30 s longest pause 0.29 s
rollback 1.7 s longest pause 0.99 s
eval, 200 queries 29 s p99 13 ms

Details in Running a migration.

Fingerprint an embedding configuration

Get the fingerprint of an embedding configuration:

$ vecshift fingerprint --provider openai --model text-embedding-3-small --dimensions 1536
openai/text-embedding-3-small@1536#a3ac94a82eca

Any change to the provider, model, dimensions, version, task type, prefix, or normalization produces a different tag, because it's a different vector space.

Documentation

Contributing

Contributions are welcome, especially new connectors and embedding providers once the contracts settle. Start with CONTRIBUTING.md. Everyone taking part is expected to follow the Code of Conduct.

To report a security issue, see SECURITY.md. Please don't open a public issue.

License

Licensed under the Apache License 2.0.

Metadata

Release files for vecshift 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for vecshift 0.3.0
File Size Uploaded
vecshift-0.3.0.tar.gz 537.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for vecshift 0.3.0
File Interpreter ABI Platform
vecshift-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 702.1 kB

Release files / vecshift-0.3.0.tar.gz

Download URL vecshift-0.3.0.tar.gz
Size 537.9 kB
Tags Source
SHA-256 checksum
How to use checksums
759a476c56ade24441f0092e730db4936b869209be5d22c1a04b55688f0402b5
BLAKE2b-256 checksum
How to use checksums
c41f1f49ec582460774c8e583bd3c9819b28a6cd455083e535428ddc09413592
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release files / vecshift-0.3.0-py3-none-any.whl

Download URL vecshift-0.3.0-py3-none-any.whl
Size 164.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
317855bc3e097613f3a5f0a8d380473d7bf8297f8b9070e8c669978edf217f61
BLAKE2b-256 checksum
How to use checksums
d4d4634dcce5a17a53d8d8caf7b5cb56bf47e09b3307b89573aff047b7f22541
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page