npm.io
4.0.1 • Published 3d ago

@pawells/nestjs-qdrant

Licence
MIT
Version
4.0.1
Deps
6
Size
128 kB
Vulns
0
Weekly
14

@pawells/nestjs-qdrant

GitHub Release CI npm version Node License: MIT GitHub Sponsors

Description

NestJS integration for the Qdrant vector database. Provides collection management, semantic vector search, and a schema-based ORM for building AI-powered applications with NestJS dependency injection.

The package exposes two programming models:

  • Service model — inject QdrantService and call Collection(name) to get a lightweight, collection-scoped service (QdrantCollection) with Search, Upsert, Delete, and GetInfo operations that pass parameters directly to the Qdrant JS client.
  • ORM model — extend the abstract QdrantModel<TPayload> base class to define a typed schema (IQdrantSchema) for a collection. Each model instance manages its own collection lifecycle on application bootstrap and exposes higher-level CRUD and search methods (Create, FindById, Find, Search, UpdateOne, DeleteOne, DeleteMany).

Both models are registered through QdrantModule, which supports synchronous (forRoot) and asynchronous (forRootAsync) configuration. Multiple named Qdrant client instances are supported for multi-tenant scenarios via forRoot/forRootAsync with a name option and forFeature for model binding.

Requirements

  • Node.js >=22.0.0
  • NestJS peer dependencies (installed separately):
    • @nestjs/common ^11.0.0
    • @nestjs/core ^11.0.0
  • Qdrant JS client (installed as a direct dependency — no separate install needed):
    • @qdrant/js-client-rest ^1.13.0

A running Qdrant instance is required at runtime. The default connection URL is http://localhost:6333.

Installation

Install the package and its required peers:

yarn add @pawells/nestjs-qdrant @nestjs/common @nestjs/core

CommonJS note: All @pawells/ packages are published as ESM ("type": "module"). If your runtime requires CommonJS, configure a bundler or use a dynamic import() call.

Quick Start

1. Configure the connection

Set the environment variables before starting the application:

QDRANT_URL=http://localhost:6333
QDRANT_API_KEY=your-api-key   # optional; omit for unauthenticated clusters
2. Register the module

Register QdrantModule in your root AppModule using forRootAsync with ConfigService (recommended) or forRoot for synchronous configuration:

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { QdrantModule } from '@pawells/nestjs-qdrant';

@Module({
	imports: [
		ConfigModule.forRoot(),
		QdrantModule.forRootAsync({
			imports: [ConfigModule],
			inject: [ConfigService],
			useFactory: (config: ConfigService) => ({
				url: config.get<string>('QDRANT_URL', 'http://localhost:6333'),
				apiKey: config.get<string>('QDRANT_API_KEY'),
			}),
		}),
	],
})
export class AppModule {}
3a. Semantic search via QdrantService (service model)

Inject QdrantService and call Collection(name) to run a vector similarity search:

import { Injectable } from '@nestjs/common';
import { QdrantService } from '@pawells/nestjs-qdrant';

@Injectable()
export class SearchService {
	constructor(private readonly qdrantService: QdrantService) {}

	async Search(embedding: number[]) {
		const collection = this.qdrantService.Collection('documents');
		return collection.Search({
			vector: embedding,
			limit: 10,
			score_threshold: 0.7,
			with_payload: true,
		});
	}
}
3b. Typed ORM model (ORM model)

Extend QdrantModel to define a schema and bind it with forFeature:

import { Injectable } from '@nestjs/common';
import { QdrantModel, IQdrantSchema } from '@pawells/nestjs-qdrant';

interface DocumentPayload {
	title: string;
	source: string;
}

@Injectable()
export class DocumentModel extends QdrantModel<DocumentPayload> {
	override readonly Collection = 'documents';
	override readonly Schema: IQdrantSchema<DocumentPayload> = {
		vectorSize: 1536,
		distance: 'Cosine',
		onCollectionExists: 'skip',
		fields: {
			title: { type: 'keyword', index: true },
			source: { type: 'keyword', index: true },
		},
	};
}

Register the model with forFeature in the module that needs it:

import { Module } from '@nestjs/common';
import { QdrantModule } from '@pawells/nestjs-qdrant';
import { DocumentModel } from './document.model.js';
import { DocumentService } from './document.service.js';

@Module({
	imports: [QdrantModule.forFeature([DocumentModel])],
	providers: [DocumentService],
})
export class DocumentModule {}

Inject the model with @InjectQdrantModel:

import { Injectable } from '@nestjs/common';
import { InjectQdrantModel } from '@pawells/nestjs-qdrant';
import { DocumentModel } from './document.model.js';

@Injectable()
export class DocumentService {
	constructor(
		@InjectQdrantModel(DocumentModel) private readonly Documents: DocumentModel,
	) {}

	async SearchDocuments(embedding: number[]) {
		return this.Documents.Search({
			vector: embedding,
			limit: 5,
			scoreThreshold: 0.7,
		});
	}
}

API Reference

Module
Symbol Kind Description
QdrantModule @Module class Dynamic NestJS module. Call forRoot(options, isGlobal?), forRootAsync(options, isGlobal?), or forFeature(models, clientName?). Registers globally by default (isGlobal = true).
QdrantModule.forRoot(options, isGlobal?)
Parameter Type Description
options TQdrantModuleOptions Qdrant client options (extends QdrantClientParams). Accepts url, apiKey, name, and any other @qdrant/js-client-rest client params.
isGlobal boolean Register as a global module (default: true).
QdrantModule.forRootAsync(options, isGlobal?)
Parameter Type Description
options IQdrantModuleAsyncOptions Async configuration. Supports useFactory, useClass, or useExisting. Includes imports, inject, and optional name for multi-tenant setups.
isGlobal boolean Register as a global module (default: true).
QdrantModule.forFeature(models, clientName?)
Parameter Type Description
models Type<unknown>[] Array of QdrantModel subclasses to register as providers.
clientName string Name of the Qdrant client to bind models to (optional; defaults to the default client).

Services
Symbol Kind Description
QdrantService Injectable class Facade over the Qdrant client. Call Collection(name) to get a QdrantCollection scoped to a named collection. Collection instances are cached after first access.
QdrantCollection Class Non-injectable, collection-scoped wrapper. Obtain instances via QdrantService.Collection(name). Exposes Search, Upsert, Delete, and GetInfo.
QdrantService methods
Method Signature Description
Collection (collectionName: string) => QdrantCollection Returns (and caches) a QdrantCollection instance. Throws BadRequestException if the name is invalid (>255 chars or non-alphanumeric/hyphen/underscore).
QdrantCollection methods
Method Signature Description
Search (params: SearchParameters) => Promise<SearchResult> Vector similarity search. params are passed directly to QdrantClient.search().
Upsert (params: UpsertParameters) => Promise<UpsertResult> Insert or update points. params are passed directly to QdrantClient.upsert().
Delete (params: DeleteParameters) => Promise<DeleteResult> Delete points by selector. params are passed directly to QdrantClient.delete().
GetInfo () => ReturnType<QdrantClient['getCollection']> Retrieve collection metadata including point count and configuration.

ORM Model
Symbol Kind Description
QdrantModel<TPayload> Abstract injectable class Base class for typed collection models. Subclass must define Collection: string and Schema: IQdrantSchema<TPayload>. Implements OnApplicationBootstrap to ensure the collection exists on startup.
QdrantModel<TPayload> methods
Method Signature Description
Create (point: IQdrantPoint<TPayload>) => Promise<void> Insert a single point (upsert).
FindById (id: string) => Promise<IQdrantPoint<TPayload> | null> Retrieve a single point by ID. Returns null if not found.
Find (options?: IQdrantFindOptions<TPayload>) => Promise<IQdrantPoint<TPayload>[]> Scroll through collection with optional filter and pagination. Default limit: 100.
Search (options: IQdrantSearchOptions<TPayload>) => Promise<IQdrantSearchResult<TPayload>[]> Vector similarity search. Default limit: 10.
UpdateOne (id: string, updates: Partial<TPayload>) => Promise<void> Merge partial payload updates into an existing point. Vector is preserved.
DeleteOne (id: string) => Promise<void> Delete a single point by ID.
DeleteMany (filter: TQdrantPayloadFilter<TPayload>) => Promise<void> Delete all points matching a payload filter.

Decorators
Symbol Kind Description
InjectQdrantClient Parameter decorator factory Inject a QdrantClient instance. Accepts an optional name string for named multi-tenant clients. Usage: @InjectQdrantClient() or @InjectQdrantClient('archive').
InjectQdrantModel Parameter decorator factory Inject a QdrantModel subclass. Accepts the model class as its argument. Usage: @InjectQdrantModel(DocumentModel).

Types and Interfaces
Symbol Kind Description
TQdrantModuleOptions Type alias Extends QdrantClientParams with an optional name field for multi-tenant client registration.
IQdrantModuleAsyncOptions Interface Async module options. Supports useFactory, useClass, useExisting, inject, imports, and name.
IQdrantOptionsFactory Interface Implement to provide a class-based async options factory. Must implement CreateQdrantOptions(): Promise<TQdrantModuleOptions> | TQdrantModuleOptions.
IQdrantSchema<TPayload> Interface Collection schema definition. Fields: vectorSize: number, distance: 'Cosine' | 'Dot' | 'Euclid' | 'Manhattan', fields, onCollectionExists?: 'skip' | 'recreate' | 'error'.
IQdrantPoint<TPayload> Interface A single vector point: id: string, vector: number[], payload: TPayload.
IQdrantSearchResult<TPayload> Interface Search result: id: string, score: number, payload: TPayload.
IQdrantSearchOptions<TPayload> Interface Search options: vector: number[], limit?: number, filter?: TQdrantPayloadFilter<TPayload>, scoreThreshold?: number.
IQdrantFindOptions<TPayload> Interface Find/scroll options: filter?: TQdrantPayloadFilter<TPayload>, limit?: number, offset?: number.
IQdrantScrollResult<TPayload> Interface Scroll result: points: IQdrantPoint<TPayload>[], nextPageOffset?: string | number.
IQdrantFieldDefinition Interface Schema field definition: type: TQdrantFieldType, index?: boolean, nullable?: boolean, description?: string.
TQdrantPayloadFilter<TPayload> Type alias Partial payload used as a filter: Partial<TPayload>.
TQdrantFieldType Type alias Payload field types: 'keyword' | 'integer' | 'float' | 'geo' | 'text' | 'bool' | 'json'.

Constants and Token Helpers
Symbol Kind Description
QDRANT_CLIENT_TOKEN string constant DI token for the default Qdrant client ('QDRANT_CLIENT').
QDRANT_MODULE_OPTIONS string constant DI token for the default module options ('QDRANT_MODULE_OPTIONS'). API key is stripped from this token.
DEFAULT_QDRANT_CLIENT_NAME string constant Default client name ('default').
MAX_COLLECTION_NAME_LENGTH number constant Maximum allowed collection name length (255).
GetQdrantClientToken Function (name?: string) => string — Returns the DI token for a named client. No name or 'default' returns 'QDRANT_CLIENT'; named returns 'QDRANT_CLIENT:{name}'.
GetQdrantModuleOptionsToken Function (name?: string) => string — Returns the DI token for a named client's options.

Errors
Symbol Kind Description
QdrantOperationError Error class Thrown when a Qdrant operation fails. Extends BaseError from @pawells/typescript-common. Default error code: 'QDRANT_OPERATION_FAILED'. Accepts { code?: string; cause?: Error } in the constructor options.

Configuration (Environment Variables)
Variable Default Required Description
QDRANT_URL http://localhost:6333 No Qdrant server URL. Use HTTPS in production. Consumed by QdrantConfig.Get('URL').
QDRANT_API_KEY No API key for authenticated Qdrant clusters. Consumed by QdrantConfig.Get('API_KEY').

QdrantConfig is a @pawells/config schema accessor. Register a provider (e.g., ConfigEnvironmentProvider.Register()) before reading values via QdrantConfig.Get('URL') or QdrantConfig.Get('API_KEY'). The recommended alternative is to pass values directly through QdrantModule.forRootAsync() using NestJS ConfigService — see Quick Start above.

License

MIT — Copyright (c) Phillip Aaron Wells. See LICENSE for details.

Keywords