{"id":11389,"library":"nestjs-opensearch","title":"NestJS OpenSearch Module","description":"The `nestjs-opensearch` package provides a dedicated module for integrating OpenSearch with the NestJS framework. It simplifies connecting to OpenSearch clusters, offering configurations for single, multiple, and asynchronously provisioned clients. The current stable version is 1.4.1, which includes support for NestJS v11 and OpenSearch client v3. Releases tend to align with major NestJS and `@opensearch-project/opensearch` peer dependency updates to maintain compatibility. Its key differentiators include leveraging NestJS's declarative module structure, providing robust dependency injection for OpenSearch clients (both default and named), and supporting both synchronous and asynchronous configuration patterns, including `useFactory` and `useClass` options. This design allows for flexible integration within various NestJS application architectures, adhering to the framework's modularity and inversion of control principles.","status":"active","version":"1.4.1","language":"javascript","source_language":"en","source_url":"https://github.com/neoatlan/nestjs-opensearch","tags":["javascript","opensearch","elasticsearch","nestjs","nest","typescript","nodejs","node"],"install":[{"cmd":"npm install nestjs-opensearch","lang":"bash","label":"npm"},{"cmd":"yarn add nestjs-opensearch","lang":"bash","label":"yarn"},{"cmd":"pnpm add nestjs-opensearch","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core NestJS framework peer dependency, required for module registration and dependency injection.","package":"@nestjs/common","optional":false},{"reason":"The official OpenSearch client library, which this module wraps and exposes.","package":"@opensearch-project/opensearch","optional":false}],"imports":[{"note":"The main NestJS module for configuring and registering OpenSearch clients.","wrong":"const OpensearchModule = require('nestjs-opensearch').OpensearchModule;","symbol":"OpensearchModule","correct":"import { OpensearchModule } from 'nestjs-opensearch';"},{"note":"Decorator used to inject `OpensearchClient` instances into services or controllers. Supports named clients.","wrong":"import InjectOpensearchClient from 'nestjs-opensearch';","symbol":"InjectOpensearchClient","correct":"import { InjectOpensearchClient } from 'nestjs-opensearch';"},{"note":"The TypeScript type definition for the injected OpenSearch client. It corresponds to the client from `@opensearch-project/opensearch`.","symbol":"OpensearchClient","correct":"import { OpensearchClient } from 'nestjs-opensearch';"},{"note":"Interface to implement when using `forRootAsync({ useClass: ... })` for custom asynchronous client option provisioning.","symbol":"OpensearchClientOptionsFactory","correct":"import { OpensearchClientOptionsFactory } from 'nestjs-opensearch';"}],"quickstart":{"code":"import { Module, Injectable } from '@nestjs/common';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { OpensearchModule, InjectOpensearchClient, OpensearchClient } from 'nestjs-opensearch';\n\n// A basic configuration factory for NestJS ConfigModule\nfunction configuration() {\n  return {\n    opensearch: {\n      node: process.env.OPENSEARCH_NODE || 'http://localhost:9200',\n      auth: {\n        username: process.env.OPENSEARCH_USERNAME || 'admin',\n        password: process.env.OPENSEARCH_PASSWORD || 'admin'\n      }\n    }\n  };\n}\n\n@Injectable()\nexport class SearchService {\n  constructor(\n    // Inject the default client (no clientName specified)\n    @InjectOpensearchClient() private readonly defaultClient: OpensearchClient,\n    // Inject a named client\n    @InjectOpensearchClient('myNamedClient') private readonly namedClient: OpensearchClient,\n  ) {}\n\n  async indexDocument(index: string, id: string, document: any): Promise<void> {\n    await this.defaultClient.index({\n      index,\n      id,\n      body: document,\n      refresh: true,\n    });\n    console.log(`Document '${id}' indexed successfully using the default client.`);\n  }\n\n  async searchDocuments(index: string, query: any): Promise<any[]> {\n    const { body } = await this.namedClient.search({\n      index,\n      body: { query },\n    });\n    console.log(`Search performed on '${index}' using 'myNamedClient'.`);\n    return body.hits.hits;\n  }\n}\n\n@Module({\n  imports: [\n    // Load configuration for the application\n    ConfigModule.forRoot({\n      load: [configuration],\n      isGlobal: true,\n    }),\n    // Configure the default OpenSearch client asynchronously\n    OpensearchModule.forRootAsync({\n      imports: [ConfigModule],\n      inject: [ConfigService],\n      useFactory: (configService: ConfigService) => ({\n        node: configService.get<string>('opensearch.node'),\n        auth: configService.get<{ username: string; password: string }>('opensearch.auth'),\n      }),\n    }),\n    // Configure a named OpenSearch client asynchronously\n    OpensearchModule.forRootAsync({\n      clientName: 'myNamedClient',\n      imports: [ConfigModule],\n      inject: [ConfigService],\n      useFactory: (configService: ConfigService) => ({\n        node: configService.get<string>('opensearch.node'),\n        auth: configService.get<{ username: string; password: string }>('opensearch.auth'),\n      }),\n    }),\n  ],\n  providers: [SearchService],\n  exports: [SearchService],\n})\nexport class AppModule {}\n\n// To bootstrap and run this application:\n// import { NestFactory } from '@nestjs/core';\n// async function bootstrap() {\n//   const app = await NestFactory.create(AppModule);\n//   await app.listen(3000);\n//   const searchService = app.get(SearchService);\n//   await searchService.indexDocument('my-test-index', 'doc1', { title: 'Hello World' });\n//   const results = await searchService.searchDocuments('my-test-index', { match_all: {} });\n//   console.log('Search results:', results);\n// }\n// bootstrap();","lang":"typescript","description":"This quickstart demonstrates how to configure default and named OpenSearch clients asynchronously using `ConfigModule` and `useFactory`. It then shows how to inject these clients into a service (`SearchService`) to perform basic indexing and searching operations, illustrating a typical NestJS integration pattern."},"warnings":[{"fix":"Instead of passing an array, call `OpensearchModule.forRootAsync()` individually for each client configuration.","message":"Passing an array of configurations to `OpensearchModule.forRootAsync()` has been deprecated since v0.3.0 and is slated for removal in future major releases. This will become a breaking change.","severity":"deprecated","affected_versions":">=0.3.0"},{"fix":"Regularly check the package's `peerDependencies` in `package.json` or its documentation and update your project's NestJS and OpenSearch client versions accordingly.","message":"This module has strict peer dependency requirements for `@nestjs/common` and `@opensearch-project/opensearch`. Ensure your project's versions of these packages fall within the supported ranges (e.g., NestJS v8-v11, OpenSearch client v1-v3 for v1.4.1) to avoid runtime errors or unexpected behavior.","severity":"gotcha","affected_versions":">=0.0.1"},{"fix":"Upgrade `nestjs-opensearch` to v0.3.1 or newer to ensure full compatibility with TypeScript v5+.","message":"Type compatibility issues with TypeScript v5 were fixed in version v0.3.1. Users on older versions of `nestjs-opensearch` might experience compilation errors if using TypeScript v5 or newer.","severity":"gotcha","affected_versions":"<0.3.1"},{"fix":"Always provide a unique `clientName` string for each distinct OpenSearch client configuration, especially when setting up multiple connections.","message":"When configuring multiple OpenSearch clients, each client must be assigned a unique `clientName` property. Failing to do so for `forRoot()` or `forRootAsync()` calls can lead to client configurations being overwritten, resulting in unexpected behavior or incorrect client injection.","severity":"gotcha","affected_versions":">=0.0.1"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure `OpensearchModule.forRoot(...)` or `OpensearchModule.forRootAsync(...)` is added to the `imports` array of the respective NestJS module (e.g., `AppModule`).","cause":"The `OpensearchModule` was not correctly imported or configured in the NestJS module where `OpensearchService` is provided or injected.","error":"Error: Nest can't resolve dependencies of the OpensearchService (?). Please make sure that the argument OpensearchClient at index [0] is available in the SearchModule context."},{"fix":"Since v0.3.0, `forRootAsync` no longer accepts an array. Call `OpensearchModule.forRootAsync()` separately for each individual client configuration. Also, verify you are using a compatible version of the library.","cause":"This usually indicates attempting to call `forRootAsync` with an array of configurations after it was deprecated, or a mismatch in how the method is expected to be called.","error":"TypeError: (0 , nestjs_opensearch_1.OpensearchModule).forRootAsync is not a function"},{"fix":"Install the necessary peer dependency: `npm install @opensearch-project/opensearch` or `yarn add @opensearch-project/opensearch`.","cause":"The core `@opensearch-project/opensearch` client library, a peer dependency, has not been installed in your project.","error":"Error: Cannot find module '@opensearch-project/opensearch' or its corresponding type declarations."},{"fix":"Verify the `node` URL(s) provided in `OpensearchModule` configuration (e.g., `http://localhost:9200`). Check network connectivity to the OpenSearch cluster and ensure any authentication credentials (username, password, API key) are correct.","cause":"The OpenSearch client failed to establish a connection to the specified node(s). This can be due to an incorrect node URL, network issues, or authentication failures.","error":"OpensearchClientError: No Living connections"}],"ecosystem":"npm"}