opensearch-project/opensearch-go

Go Client for OpenSearch

Go

313

1,018 commits

updated Oct 9, 2026

See the code

README

Go Reference Build Unit Integration codecov Chat PRs welcome!

OpenSearch logo

OpenSearch Go Client

Welcome!

opensearch-go is a community-driven, open source fork of go-elasticsearch licensed under the Apache v2.0 License. For more information, see opensearch.org.

The client supports automatic node discovery, request-based connection routing, and role-aware node selection. See the User Guide and guides for usage examples and configuration options.

Upgrading across a major version? The osapilint tool automates most of the API-shape changes (type, method, and field renames) across the v2 -> v5 hops - see cmd/osapilint/README.md and the per-version deep-dives (v3 -> v4, v4 -> v5).

Quickstart

Install the client:

go get github.com/opensearch-project/opensearch-go/v5

A small CRUD example - create an index, index a document, read it back, search for it, then delete it:

package main

import (
	"context"
	"fmt"
	"log"
	"strings"

	"github.com/opensearch-project/opensearch-go/v5"
	"github.com/opensearch-project/opensearch-go/v5/opensearchapi"
)

func main() {
	client, err := opensearchapi.NewClient(opensearchapi.Config{
		Client: opensearch.Config{
			Addresses: []string{"https://localhost:9200"},
			Username:  "admin",
			Password:  "myStrongPassword123!",
		},
	})
	if err != nil {
		log.Fatal(err)
	}

	ctx := context.Background()

	// Create an index.
	if _, err = client.Indices.Create(ctx, opensearchapi.IndicesCreateReq{
		Index:      "movies",
		BodyReader: strings.NewReader(`{"settings": {"number_of_shards": 1}}`),
	}); err != nil {
		log.Fatal(err)
	}

	// Index two documents. Omitting ID lets OpenSearch generate one, returned as
	// resp.ID. This keeps the example simple, but in production prefer a
	// client-supplied ID derived from your data's natural key: it makes indexing
	// idempotent (a retry overwrites rather than duplicates) and lets you address
	// the document later without storing the server's ID. Refresh=true makes the
	// documents immediately searchable, which is convenient here but hurts
	// indexing throughput at scale - prefer the default refresh in production.
	movies := []string{
		`{"title": "WarGames", "year": 1983}`,
		`{"title": "Sneakers", "year": 1992}`,
	}
	var ids []string
	for _, doc := range movies {
		indexed, err := client.Doc.Index(ctx, opensearchapi.IndexReq{
			Index:  "movies",
			Body:   strings.NewReader(doc),
			Params: &opensearchapi.IndexParams{Refresh: "true"},
		})
		if err != nil {
			log.Fatal(err)
		}
		ids = append(ids, indexed.ID)
	}

	// Get the first document back by its generated ID.
	got, err := client.Doc.Get(ctx, opensearchapi.GetReq{Index: "movies", ID: ids[0]})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("get id=%s found=%v source=%q\n", got.ID, got.Found, got.Source)

	// Search for WarGames; with two documents indexed, this confirms we get the
	// right one back rather than just "a" result.
	search, err := client.Search(ctx, &opensearchapi.SearchReq{
		Indices:    []string{"movies"},
		BodyReader: strings.NewReader(`{"query": {"match": {"title": "WarGames"}}}`),
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%d hit(s)\n", len(search.Hits.Hits))
	for _, hit := range search.Hits.Hits {
		fmt.Printf("  source=%q\n", hit.Source)
	}

	// Delete both documents.
	for _, id := range ids {
		if _, err = client.Doc.Delete(ctx, opensearchapi.DeleteReq{Index: "movies", ID: id}); err != nil {
			log.Fatal(err)
		}
	}
}

Next steps:

  • Security - TLS, certificate verification, and authentication. The example above uses a plaintext-friendly local setup; read this before connecting to a real cluster.
  • Environment Variables - the canonical reference for every OPENSEARCH_GO_* runtime override.
  • opensearchapi usage README - client creation, requests, responses, query parameters, and partial-failure errors.
  • Debug logging - OPENSEARCH_GO_LOG=debug prints the client's internal records to stderr. To route log messages, configure a log-zerolog or log-slog logger. See Cost for additional recommendations.
  • Guides - task-oriented references (indexing, search, bulk, routing, discovery, error handling, and more).
  • API reference on pkg.go.dev - the full generated API surface.

Project Resources

Code of Conduct

This project has adopted the Amazon Open Source Code of Conduct. For more information see the Code of Conduct FAQ, or contact opensource-codeofconduct@amazon.com with any additional questions or comments.

License

This project is licensed under the Apache v2.0 License.

Copyright OpenSearch Contributors. See NOTICE for details.

opensearch-project/opensearch-go

Go Client for OpenSearch

Go

313

1,018 commits

updated Oct 9, 2026

See the code

README

Go Reference Build Unit Integration codecov Chat PRs welcome!

OpenSearch logo

OpenSearch Go Client

Welcome!

opensearch-go is a community-driven, open source fork of go-elasticsearch licensed under the Apache v2.0 License. For more information, see opensearch.org.

The client supports automatic node discovery, request-based connection routing, and role-aware node selection. See the User Guide and guides for usage examples and configuration options.

Upgrading across a major version? The osapilint tool automates most of the API-shape changes (type, method, and field renames) across the v2 -> v5 hops - see cmd/osapilint/README.md and the per-version deep-dives (v3 -> v4, v4 -> v5).

Quickstart

Install the client:

go get github.com/opensearch-project/opensearch-go/v5

A small CRUD example - create an index, index a document, read it back, search for it, then delete it:

package main

import (
	"context"
	"fmt"
	"log"
	"strings"

	"github.com/opensearch-project/opensearch-go/v5"
	"github.com/opensearch-project/opensearch-go/v5/opensearchapi"
)

func main() {
	client, err := opensearchapi.NewClient(opensearchapi.Config{
		Client: opensearch.Config{
			Addresses: []string{"https://localhost:9200"},
			Username:  "admin",
			Password:  "myStrongPassword123!",
		},
	})
	if err != nil {
		log.Fatal(err)
	}

	ctx := context.Background()

	// Create an index.
	if _, err = client.Indices.Create(ctx, opensearchapi.IndicesCreateReq{
		Index:      "movies",
		BodyReader: strings.NewReader(`{"settings": {"number_of_shards": 1}}`),
	}); err != nil {
		log.Fatal(err)
	}

	// Index two documents. Omitting ID lets OpenSearch generate one, returned as
	// resp.ID. This keeps the example simple, but in production prefer a
	// client-supplied ID derived from your data's natural key: it makes indexing
	// idempotent (a retry overwrites rather than duplicates) and lets you address
	// the document later without storing the server's ID. Refresh=true makes the
	// documents immediately searchable, which is convenient here but hurts
	// indexing throughput at scale - prefer the default refresh in production.
	movies := []string{
		`{"title": "WarGames", "year": 1983}`,
		`{"title": "Sneakers", "year": 1992}`,
	}
	var ids []string
	for _, doc := range movies {
		indexed, err := client.Doc.Index(ctx, opensearchapi.IndexReq{
			Index:  "movies",
			Body:   strings.NewReader(doc),
			Params: &opensearchapi.IndexParams{Refresh: "true"},
		})
		if err != nil {
			log.Fatal(err)
		}
		ids = append(ids, indexed.ID)
	}

	// Get the first document back by its generated ID.
	got, err := client.Doc.Get(ctx, opensearchapi.GetReq{Index: "movies", ID: ids[0]})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("get id=%s found=%v source=%q\n", got.ID, got.Found, got.Source)

	// Search for WarGames; with two documents indexed, this confirms we get the
	// right one back rather than just "a" result.
	search, err := client.Search(ctx, &opensearchapi.SearchReq{
		Indices:    []string{"movies"},
		BodyReader: strings.NewReader(`{"query": {"match": {"title": "WarGames"}}}`),
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%d hit(s)\n", len(search.Hits.Hits))
	for _, hit := range search.Hits.Hits {
		fmt.Printf("  source=%q\n", hit.Source)
	}

	// Delete both documents.
	for _, id := range ids {
		if _, err = client.Doc.Delete(ctx, opensearchapi.DeleteReq{Index: "movies", ID: id}); err != nil {
			log.Fatal(err)
		}
	}
}

Next steps:

  • Security - TLS, certificate verification, and authentication. The example above uses a plaintext-friendly local setup; read this before connecting to a real cluster.
  • Environment Variables - the canonical reference for every OPENSEARCH_GO_* runtime override.
  • opensearchapi usage README - client creation, requests, responses, query parameters, and partial-failure errors.
  • Debug logging - OPENSEARCH_GO_LOG=debug prints the client's internal records to stderr. To route log messages, configure a log-zerolog or log-slog logger. See Cost for additional recommendations.
  • Guides - task-oriented references (indexing, search, bulk, routing, discovery, error handling, and more).
  • API reference on pkg.go.dev - the full generated API surface.

Project Resources

Code of Conduct

This project has adopted the Amazon Open Source Code of Conduct. For more information see the Code of Conduct FAQ, or contact opensource-codeofconduct@amazon.com with any additional questions or comments.

License

This project is licensed under the Apache v2.0 License.

Copyright OpenSearch Contributors. See NOTICE for details.

Project health

Overall

7.2/10

Maintained

10/10

Code review

10/10
OpenSSF Scorecard

Latest release

v4.8.0 · Sep 24, 2026

Releases this year

6

Significant stargazers

Abrar

5 followers · starred Aug 2026

rrreeezzz

19 followers · starred Feb 2024

Sanket Singh

46 followers · starred Sep 2024

Kota

38 followers · starred Jun 2022