Migrating from pinecone-ruby to vectra-client
This guide helps you migrate from the official pinecone-ruby gem to vectra-client.
Why Migrate?
- Multi-provider support: Switch between Pinecone, Qdrant, Weaviate, pgvector without code changes
- Production patterns: Built-in middleware, retry logic, circuit breakers
- Better testing: In-memory provider for fast tests
- ActiveRecord integration:
has_vectorDSL for Rails apps
Step 1: Update Gemfile
# Remove
gem 'pinecone-ruby'
# Add
gem 'vectra-client'
Then run:
bundle install
Step 2: Update Client Initialization
Before (pinecone-ruby)
require 'pinecone'
client = Pinecone::Client.new(
api_key: ENV['PINECONE_API_KEY'],
environment: 'us-west-4'
)
After (vectra-client)
require 'vectra'
client = Vectra::Client.new(
provider: :pinecone,
api_key: ENV['PINECONE_API_KEY'],
environment: 'us-west-4'
)
Step 3: Update Method Calls
Upsert
Before:
index = client.index('my-index')
index.upsert(
vectors: [
{ id: 'vec1', values: [0.1, 0.2, 0.3], metadata: { title: 'Hello' } }
],
namespace: 'default'
)
After:
client.upsert(
index: 'my-index',
vectors: [
{ id: 'vec1', values: [0.1, 0.2, 0.3], metadata: { title: 'Hello' } }
],
namespace: 'default'
)
Query
Before:
index = client.index('my-index')
results = index.query(
vector: [0.1, 0.2, 0.3],
top_k: 10,
namespace: 'default',
filter: { category: 'docs' }
)
After:
results = client.query(
index: 'my-index',
vector: [0.1, 0.2, 0.3],
top_k: 10,
namespace: 'default',
filter: { category: 'docs' }
)
Fetch
Before:
index = client.index('my-index')
vectors = index.fetch(ids: ['vec1', 'vec2'], namespace: 'default')
After:
vectors = client.fetch(
index: 'my-index',
ids: ['vec1', 'vec2'],
namespace: 'default'
)
Delete
Before:
index = client.index('my-index')
index.delete(ids: ['vec1', 'vec2'], namespace: 'default')
After:
client.delete(
index: 'my-index',
ids: ['vec1', 'vec2'],
namespace: 'default'
)
Step 4: Index Management
List Indexes
Before:
indexes = client.list_indexes
After:
indexes = client.list_indexes
# Returns Array<Hash> with index details
Create Index
Before:
client.create_index(
name: 'my-index',
dimension: 1536,
metric: 'cosine'
)
After:
client.create_index(
name: 'my-index',
dimension: 1536,
metric: 'cosine'
)
Describe Index
Before:
index_info = client.describe_index('my-index')
After:
index_info = client.describe_index(index: 'my-index')
Step 5: Response Format Differences
Query Results
Before (pinecone-ruby):
results.matches.each do |match|
puts match['id']
puts match['score']
puts match['metadata']
end
After (vectra-client):
results.each do |match|
puts match.id # String
puts match.score # Float
puts match.metadata # Hash
end
# Or use helper methods
results.ids # Array of IDs
results.scores # Array of scores
results.first # First match
Fetch Results
Before:
vectors = index.fetch(ids: ['vec1'])
vectors['vec1']['values']
After:
vectors = client.fetch(index: 'my-index', ids: ['vec1'])
vectors['vec1'].values # Vectra::Vector object
Step 6: Error Handling
Vectra uses the same error classes where possible, but wraps them in Vectra:: namespace:
Pinecone::ApiError→Vectra::Error(or specific subclasses)Pinecone::ConfigurationError→Vectra::ConfigurationErrorPinecone::NotFoundError→Vectra::NotFoundError
Step 7: Advanced Features
Default Index/Namespace
Vectra supports default index and namespace:
client = Vectra::Client.new(
provider: :pinecone,
api_key: ENV['PINECONE_API_KEY'],
environment: 'us-west-4',
index: 'my-index', # Default index
namespace: 'default' # Default namespace
)
# Now you can omit index/namespace:
client.upsert(vectors: [...])
client.query(vector: emb, top_k: 10)
Middleware
Add logging, retry, cost tracking:
Vectra::Client.use Vectra::Middleware::Logging
Vectra::Client.use Vectra::Middleware::Retry, max_attempts: 5
Multi-tenant Support
client.for_tenant("acme") do |c|
c.upsert(vectors: [...])
c.query(vector: emb, top_k: 10)
end
Migration Checklist
- Update
Gemfile(removepinecone-ruby, addvectra-client) - Update client initialization
- Replace
client.index('name')pattern with direct method calls - Update query result iteration (use
match.idinstead ofmatch['id']) - Update fetch result access (use
.valuesinstead of['values']) - Test all operations (upsert, query, fetch, delete)
- Update error handling if needed
- Consider using default index/namespace for cleaner code