Skip to main content

Installation

Install via npm:
npm install @qdrant/js-client-rest
Or with yarn:
yarn add @qdrant/js-client-rest

Quick Start

import { QdrantClient } from '@qdrant/js-client-rest';

const client = new QdrantClient({ url: 'http://localhost:6333' });

// Create collection
await client.createCollection('my_collection', {
  vectors: {
    size: 384,
    distance: 'Cosine',
  },
});

// Upsert points
await client.upsert('my_collection', {
  points: [
    {
      id: 1,
      vector: [0.05, 0.61, 0.76, 0.74],
      payload: { city: 'Berlin', country: 'Germany' },
    },
    {
      id: 2,
      vector: [0.19, 0.81, 0.75, 0.11],
      payload: { city: 'London', country: 'UK' },
    },
  ],
});

// Search
const results = await client.search('my_collection', {
  vector: [0.2, 0.1, 0.9, 0.7],
  limit: 3,
});

console.log(results);

Repository

GitHub Repository

Official JavaScript client: qdrant/qdrant-js

Client Initialization

Basic Connection

import { QdrantClient } from '@qdrant/js-client-rest';

// Connect to local instance
const client = new QdrantClient({
  url: 'http://localhost:6333',
});

// Connect to Qdrant Cloud
const cloudClient = new QdrantClient({
  url: 'https://your-cluster.cloud.qdrant.io',
  apiKey: 'your-api-key',
});

With Custom Options

const client = new QdrantClient({
  url: 'http://localhost:6333',
  apiKey: 'your-api-key',
  timeout: 30000, // Request timeout in ms
  headers: {
    'Custom-Header': 'value',
  },
});

TypeScript Support

The client has full TypeScript definitions:
import { QdrantClient, Schemas } from '@qdrant/js-client-rest';

type PointPayload = {
  title: string;
  category: string;
  views: number;
  tags: string[];
};

const client = new QdrantClient({ url: 'http://localhost:6333' });

// Type-safe point structure
const point: Schemas['PointStruct'] = {
  id: 1,
  vector: [0.1, 0.2, 0.3],
  payload: {
    title: 'Document 1',
    category: 'technology',
    views: 1500,
    tags: ['ai', 'ml'],
  } as PointPayload,
};

await client.upsert('my_collection', {
  points: [point],
});

// Type-safe search results
const results = await client.search('my_collection', {
  vector: [0.2, 0.1, 0.9],
  limit: 10,
});

results.forEach((result) => {
  console.log(result.id);
  console.log(result.score);
  const payload = result.payload as PointPayload;
  console.log(payload.title);
});

Collection Management

Create Collection

// Single vector
await client.createCollection('my_collection', {
  vectors: {
    size: 768,
    distance: 'Cosine',
    on_disk: false,
  },
});

// Multiple named vectors
await client.createCollection('multi_vector', {
  vectors: {
    text: {
      size: 768,
      distance: 'Cosine',
    },
    image: {
      size: 512,
      distance: 'Euclid',
    },
  },
});

Create with HNSW Config

await client.createCollection('optimized', {
  vectors: {
    size: 384,
    distance: 'Cosine',
    hnsw_config: {
      m: 16,
      ef_construct: 100,
      full_scan_threshold: 10000,
    },
  },
  optimizers_config: {
    default_segment_number: 2,
    indexing_threshold: 50000,
  },
  replication_factor: 2,
  write_consistency_factor: 1,
});

Get Collection Info

const info = await client.getCollection('my_collection');

console.log(`Status: ${info.status}`);
console.log(`Vectors count: ${info.vectors_count}`);
console.log(`Points count: ${info.points_count}`);
console.log(`Segments: ${info.segments_count}`);

List Collections

const collections = await client.getCollections();

collections.collections.forEach((collection) => {
  console.log(collection.name);
});

Update Collection

await client.updateCollection('my_collection', {
  optimizers_config: {
    indexing_threshold: 50000,
    memmap_threshold: 100000,
  },
});

Delete Collection

await client.deleteCollection('my_collection');

Point Operations

Upsert Points

import { v4 as uuidv4 } from 'uuid';

await client.upsert('my_collection', {
  points: [
    {
      id: uuidv4(), // UUID string
      vector: [0.05, 0.61, 0.76, 0.74],
      payload: {
        title: 'Document 1',
        category: 'technology',
        views: 1500,
        tags: ['ai', 'ml', 'vector-db'],
      },
    },
    {
      id: 2, // Integer ID
      vector: [0.19, 0.81, 0.75, 0.11],
      payload: { title: 'Document 2' },
    },
  ],
  wait: true, // Wait for operation to complete
});

Batch Upsert

const batchSize = 100;
const totalPoints = 10000;

for (let i = 0; i < totalPoints; i += batchSize) {
  const points = Array.from({ length: batchSize }, (_, j) => ({
    id: i + j,
    vector: Array.from({ length: 384 }, () => Math.random()),
    payload: { index: i + j },
  }));

  await client.upsert('my_collection', {
    points,
    wait: false, // Don't wait for faster throughput
  });
}

Get Points

const points = await client.retrieve('my_collection', {
  ids: [1, 2, 3],
  with_payload: true,
  with_vector: true,
});

points.forEach((point) => {
  console.log(`ID: ${point.id}`);
  console.log(`Vector: ${point.vector}`);
  console.log(`Payload:`, point.payload);
});

Delete Points

// Delete by IDs
await client.delete('my_collection', {
  points: [1, 2, 3],
});

// Delete by filter
await client.delete('my_collection', {
  filter: {
    must: [
      {
        key: 'category',
        match: { value: 'outdated' },
      },
    ],
  },
});

Search Operations

const results = await client.search('my_collection', {
  vector: [0.2, 0.1, 0.9, 0.7],
  limit: 10,
  with_payload: true,
  with_vector: false,
});

results.forEach((result) => {
  console.log(result.id, result.score);
  console.log(result.payload);
});

Search with Filtering

const results = await client.search('my_collection', {
  vector: [0.2, 0.1, 0.9, 0.7],
  filter: {
    must: [
      {
        key: 'category',
        match: { value: 'technology' },
      },
      {
        key: 'views',
        range: {
          gte: 1000,
          lt: 10000,
        },
      },
    ],
  },
  limit: 5,
  score_threshold: 0.7,
});

Search with Parameters

const results = await client.search('my_collection', {
  vector: [0.2, 0.1, 0.9, 0.7],
  limit: 20,
  params: {
    hnsw_ef: 128, // Higher ef for better recall
    exact: false, // Use approximate search
    quantization: {
      ignore: false,
      rescore: true,
      oversampling: 2.0,
    },
  },
});
const results = await client.searchBatch('my_collection', {
  searches: [
    {
      vector: [0.2, 0.1, 0.9, 0.7],
      limit: 5,
      filter: {
        must: [{ key: 'category', match: { value: 'tech' } }],
      },
    },
    {
      vector: [0.5, 0.3, 0.2, 0.8],
      limit: 10,
    },
  ],
});

results.forEach((batch, index) => {
  console.log(`Results for query ${index}:`);
  batch.forEach((point) => console.log(point.id, point.score));
});

Recommendations

Basic Recommendations

const results = await client.recommend('my_collection', {
  positive: [1, 2, 3], // Point IDs to use as positive examples
  negative: [10], // Point IDs to avoid
  limit: 10,
});

Recommend with Strategy

const results = await client.recommend('my_collection', {
  positive: [1, 2],
  negative: [10],
  strategy: 'best_score', // or 'average_vector'
  limit: 5,
  filter: {
    must: [{ key: 'category', match: { value: 'tech' } }],
  },
});

Batch Recommendations

const results = await client.recommendBatch('my_collection', {
  searches: [
    {
      positive: [1, 2],
      negative: [10],
      limit: 5,
    },
    {
      positive: [3, 4, 5],
      limit: 10,
    },
  ],
});

Query API (Universal)

// Hybrid search with fusion
const results = await client.query('my_collection', {
  prefetch: [
    {
      query: [0.1, 0.2, 0.3], // Dense vector
      using: 'dense',
      limit: 100,
    },
    {
      query: { indices: [1, 5, 10], values: [0.5, 0.3, 0.2] }, // Sparse vector
      using: 'sparse',
      limit: 100,
    },
  ],
  query: { fusion: 'rrf' }, // Reciprocal Rank Fusion
  limit: 10,
});

Payload Operations

Set Payload

await client.setPayload('my_collection', {
  payload: {
    new_field: 'value',
    updated_at: '2024-01-01',
  },
  points: [1, 2, 3],
});

Overwrite Payload

await client.overwritePayload('my_collection', {
  payload: { only_field: 'value' },
  points: [1, 2],
});

Delete Payload Keys

await client.deletePayload('my_collection', {
  keys: ['old_field', 'deprecated'],
  points: [1, 2, 3],
});

Clear Payload

await client.clearPayload('my_collection', {
  points: [1, 2, 3],
});

Scroll (Pagination)

let offset: string | number | null = null;
const allPoints = [];

while (true) {
  const result = await client.scroll('my_collection', {
    limit: 100,
    offset: offset || undefined,
    with_payload: true,
    filter: {
      must: [{ key: 'category', match: { value: 'tech' } }],
    },
  });

  allPoints.push(...result.points);
  offset = result.next_page_offset;

  if (!offset) break;
}

console.log(`Total points: ${allPoints.length}`);

Payload Indexing

// Create keyword index
await client.createPayloadIndex('my_collection', {
  field_name: 'category',
  field_schema: 'keyword',
});

// Create text index for full-text search
await client.createPayloadIndex('my_collection', {
  field_name: 'description',
  field_schema: {
    type: 'text',
    tokenizer: 'word',
    lowercase: true,
    min_token_len: 2,
    max_token_len: 20,
  },
});

// Delete index
await client.deletePayloadIndex('my_collection', 'category');

Snapshots

Create Snapshot

const snapshot = await client.createSnapshot('my_collection');
console.log(`Snapshot name: ${snapshot.name}`);

List Snapshots

const snapshots = await client.listSnapshots('my_collection');
snapshots.forEach((snapshot) => {
  console.log(snapshot.name);
});

Recover from Snapshot

await client.recoverSnapshot('my_collection', {
  location: 'http://localhost:6333/snapshots/my_collection/snapshot.snapshot',
});

Error Handling

import { QdrantClient } from '@qdrant/js-client-rest';

const client = new QdrantClient({ url: 'http://localhost:6333' });

try {
  await client.getCollection('nonexistent');
} catch (error: any) {
  if (error.status === 404) {
    console.log('Collection not found');
  } else {
    console.error(`Error: ${error.status} - ${error.message}`);
  }
}

Usage with Node.js

const { QdrantClient } = require('@qdrant/js-client-rest');

const client = new QdrantClient({ url: 'http://localhost:6333' });

async function main() {
  // Create collection
  await client.createCollection('my_collection', {
    vectors: {
      size: 384,
      distance: 'Cosine',
    },
  });

  // Upsert points
  await client.upsert('my_collection', {
    points: [
      {
        id: 1,
        vector: [0.05, 0.61, 0.76, 0.74],
        payload: { name: 'Document 1' },
      },
    ],
  });

  // Search
  const results = await client.search('my_collection', {
    vector: [0.2, 0.1, 0.9, 0.7],
    limit: 5,
  });

  console.log(results);
}

main().catch(console.error);

Usage with Browser

<!DOCTYPE html>
<html>
  <head>
    <script type="module">
      import { QdrantClient } from 'https://cdn.jsdelivr.net/npm/@qdrant/js-client-rest/+esm';

      const client = new QdrantClient({
        url: 'http://localhost:6333',
      });

      async function search() {
        const results = await client.search('my_collection', {
          vector: [0.2, 0.1, 0.9, 0.7],
          limit: 5,
        });
        console.log(results);
      }

      search();
    </script>
  </head>
  <body>
    <h1>Qdrant Browser Example</h1>
  </body>
</html>

Advanced Filtering

// Complex filter with nested conditions
const results = await client.search('my_collection', {
  vector: [0.2, 0.1, 0.9],
  filter: {
    must: [
      {
        key: 'category',
        match: { value: 'technology' },
      },
    ],
    should: [
      {
        key: 'views',
        range: { gte: 10000 },
      },
      {
        key: 'featured',
        match: { value: true },
      },
    ],
    must_not: [
      {
        key: 'status',
        match: { value: 'archived' },
      },
    ],
  },
  limit: 10,
});

Best Practices

Performance tips:
  • Use batch operations for multiple points
  • Set wait: false for faster upserts
  • Create payload indexes before filtering
  • Use appropriate batch sizes (100-1000 points)
Common issues:
  • Always handle errors with try-catch
  • Ensure vector dimensions match collection config
  • Use UUID strings or integers for point IDs
  • Handle pagination when scrolling large datasets

Next Steps

Python Client

Python client documentation

Rust Client

Rust client library

Build docs developers (and LLMs) love