Model or dataset
openai/openai-go avatar
openai/openai-go

openai/openai-go: the official Go client for the OpenAI API, and what v3 expects from your toolchain

The official Go library for the OpenAI API

3,481 stars351 forksGoApache-2.0

At a glance

What is it?
The openai-go library wraps the OpenAI REST API for Go programs, defaults to the Responses API, and since v3.45.0 requires Go 1.25. This review covers installation, the streaming and tool-calling paths, the version pinning you may need, and the cases where a plain HTTP call is the better choice.
Who is it for?
Adopt openai-go if your service is written in Go and you want typed Responses, streaming and tool-calling without hand-rolling HTTP and JSON. Do not adopt it if you are on Go 1.22 to 1.24 and cannot pin v3.44.0, or if you only need one endpoint and want to keep your dependency graph empty.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What openai-go actually solves for Go services

Calling the OpenAI REST API from Go by hand is not hard, but it is tedious in a specific way. You write request structs, you handle multipart uploads for audio, you parse server-sent events for streaming, you thread a previous response ID through follow-up turns, and you keep all of that in sync with an API that moves. The openai-go library is the official Go client for that API, and its job is to absorb that bookkeeping so your code talks in Go types instead of raw JSON.

It is aimed at application developers rather than researchers. The repository ships an examples/ directory covering chat completions, streaming, tool calling, structured outputs, image generation, audio transcription and text to speech, fine-tuning, vector store file batches and video generation. There are also examples for Azure and for Bedrock, which tells you the client is meant to sit inside production services that may not point at OpenAI's own endpoint at all. If you are writing a CLI, a backend worker or a service that calls models on behalf of other code, that is the intended audience.

How the client is structured: one client, service namespaces, typed params

The entry point is openai.NewClient, which returns a client that carries configuration such as the API key and any per-request options. From there the API is split into namespaces: client.Responses, client.Conversations, client.Chat, and so on. Each namespace exposes methods that take a params struct, so responses.ResponseNewParams for a Responses call, and each method takes a context.Context as its first argument.

The README states that the primary API for interacting with OpenAI models is the Responses API, and the top-level usage example reflects that: a single call to client.Responses.New with an input union and a model. Parameters that are optional are expressed as pointers through helpers like openai.String, which is why the example wraps the question and the previous response ID. The result object carries a convenience method, resp.OutputText(), for the common case where you want the text and nothing else.

Streaming is a separate constructor rather than a flag. client.Responses.NewStreaming returns a stream you drive with a Next/Current/Err loop and close with defer. That shape is idiomatic Go, and it means a streaming call cannot be mistaken for a blocking one at the call site. The dependency list in go.mod is small for a client of this scope: tidwall/gjson and sjson for JSON handling, coder/websocket, and the Azure and AWS SDK pieces that back the alternate authentication paths.

Installing openai-go and making a first Responses call

The import path carries the major version, so the package is imported as github.com/openai/openai-go/v3 but referred to in code as openai. The README shows the import block first, and then a go get command for pinning a specific SDK version. Pin explicitly if you care about reproducible builds, because the module path does not pin anything for you.

bash
go get -u 'github.com/openai/openai-go/[email protected]'

That command fetches the tagged release listed in the README. Note the quoting: the @v3.66.0 suffix is part of the argument and the shell will not expand it inside single quotes.

The minimal program below is the README's own example, trimmed to the parts that matter. It builds a client, sends a string input to the Responses API, and prints the text output. The API key defaults to the OPENAI_API_KEY environment variable if you do not pass option.WithAPIKey.

go
package main

import (
	"context"

	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/responses"
)

func main() {
	ctx := context.Background()
	client := openai.NewClient()

	resp, err := client.Responses.New(ctx, responses.ResponseNewParams{
		Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("Write me a haiku about computers")},
		Model: openai.ChatModelGPT5_2,
	})
	if err != nil {
		panic(err)
	}

	println(resp.OutputText())
}

Run that with OPENAI_API_KEY set and you should see the model's text on stdout. If you get an authentication error instead, the key was not picked up from the environment; the README notes the default lookup is os.LookupEnv("OPENAI_API_KEY").

Multi-turn conversations do not resend the whole history. You pass the previous response's ID back in, as the README's multi-turn example shows with PreviousResponseID: openai.String(response.ID). The Conversations API is the alternative when you want the server to own the thread: you create a conversation, pass it in the Conversation field on each call, and list its items afterwards with client.Conversations.Items.List.

Streaming and tool calling: the two paths that decide whether you need the SDK

Streaming is where a typed client earns its place. The README's streaming example constructs the stream, defers Close, loops on stream.Next(), reads stream.Current() and prints its Delta field, then checks stream.Err() after the loop. That is a small amount of code for something that is genuinely unpleasant to implement over raw server-sent events, and the error handling is in the right place: after the loop, not inside it.

Tool calling is the other path worth reading before you adopt. The README example declares a function tool with a name, a description and a JSON Schema parameters map, sends it in the Tools slice, then walks response.Output looking for items whose Type is "function_call". When it finds one it calls item.AsFunctionCall(), unmarshals toolCall.Arguments into a map, runs the local function, and sends the result back as a function call output item with the matching CallID and the previous response ID. The important detail is that the SDK gives you the union type and the accessor; you still own the dispatch loop and the argument unmarshalling. Nothing here hides the control flow from you, which is the right call for a client library but does mean a tool-calling agent is real code, not a one-liner.

The Go version floor is the constraint that will bite you first

This is the limitation to check before anything else. The README states that SDK v3.45.0 and later require Go 1.25 or later, and that applications which must remain on Go 1.22 through 1.24 should pin SDK v3.44.0, described as the final compatible release. It goes further: older SDK releases receive no guaranteed fixes or security backports. So the choice is not between a current version and a slightly older one. It is between upgrading your toolchain and running a client that the project has explicitly said it will not backport fixes to. The repository also carries a GO_VERSION_POLICY.md for the supported release window, and go.mod declares go 1.25.0, so the floor is enforced by the module itself, not just documented.

The second thing to weigh is the breaking-change warning at the top of the README. It says the latest version of this package has small and limited breaking changes and points at CHANGELOG.md. A client that tracks a fast-moving API will have releases that change method signatures, and the versioned import path means a major bump is a real migration rather than a silent upgrade. There is a MIGRATION.md in the repository for exactly that reason.

Finally, consider whether you need the SDK at all. If your program makes one blocking call to one endpoint and parses one field, the dependency brings in the Azure and AWS SDK trees as indirect requirements, and a net/http request with a JSON body is a smaller thing to own. The library pays off when you use streaming, tools, or several namespaces together.

Alternatives: what changes if you drop the client

The most direct alternative is no client at all: build the request with net/http and encoding/json against the REST API documented at platform.openai.com. The difference in approach is total. You own the request and response types, the retry behaviour, the streaming parser and the schema of every field, and you get zero transitive dependencies and no Go version floor beyond what your own module declares. What you give up is the typed unions, the stream loop, and the fact that a field rename shows up as a compile error rather than a runtime surprise.

Within the same repository there is a second kind of alternative: the examples/azure and examples/bedrock directories show the client pointed at non-OpenAI backends, so choosing openai-go does not force you onto one provider. That matters if your reason for avoiding an SDK was portability rather than dependency weight. The repository layout also shows a large admin surface, with files for organization projects, API keys, rate limits, groups and audit logs, which is a different use case from inference: if you are building internal tooling around organization administration rather than calling models, that part of the client is the relevant one and the Responses examples are not.

Licence, releases and the cost of staying current

The library is Apache-2.0, which permits commercial use, modification and redistribution provided you keep the licence and notices, and it includes a patent grant. That is a permissive licence and it is compatible with the way most Go services are distributed, but the usual Apache-2.0 obligations still apply to anything you vendor. This is a description of the licence text, not legal advice.

Upgrade cost is the part teams underestimate. Releases arrive frequently: v3.66.0, v3.65.0 and v3.64.3 all landed within days of each other, and the last push to the repository was on 2026-09-23. The project uses release-please, visible in the README's version markers and the .release-please-manifest.json file at the repository root, so version bumps are automated and the changelog is generated. That means the changelog is the artifact to read, and pinning a version is the only thing standing between you and an automated bump. Pin in go.mod, and treat a version bump as a change that needs a test run rather than a routine dependency refresh.

Editorial conclusion

Adopt openai-go if your service is written in Go and you want typed Responses, streaming and tool-calling without hand-rolling HTTP and JSON. Do not adopt it if you are on Go 1.22 to 1.24 and cannot pin v3.44.0, or if you only need one endpoint and want to keep your dependency graph empty. Before you commit, run go get -u 'github.com/openai/openai-go/[email protected]' against your module, confirm your toolchain reports go 1.25.0 or later, and read CHANGELOG.md for the breaking changes the README warns about.

Frequently asked questions

What is openai/openai-go?

It is the official Go library for the OpenAI REST API, imported as github.com/openai/openai-go/v3 and used as openai in code. The README describes it as providing convenient access to the OpenAI REST API from applications written in Go, with the Responses API as the primary interface for interacting with models.

How do I install the openai-go SDK?

Add it to your module with the versioned import path, for example go get -u 'github.com/openai/openai-go/[email protected]', and import github.com/openai/openai-go/v3 in your source. The README shows both the import block and the go get command for pinning a specific SDK version.

Which Go version does openai-go require?

SDK v3.45.0 and later require Go 1.25 or later, and go.mod declares go 1.25.0. Applications that must stay on Go 1.22 through 1.24 should pin SDK v3.44.0, which the README calls the final compatible release and notes receives no guaranteed fixes or security backports.

How does openai-go handle multi-turn conversations?

You pass the previous response's ID back in through PreviousResponseID, as shown in the README's multi-turn example, rather than resending the full history. Alternatively the Conversations API lets you create a conversation, pass it in the Conversation field of each request, and list its items afterwards.

What licence is openai-go released under?

The repository is licensed under Apache-2.0, which permits commercial use, modification and redistribution subject to keeping the licence and notices. The repository root contains a LICENSE file and a SECURITY.md.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. openai/openai-go on GitHub
  4. README
  5. Releases
For maintainers

Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/openai-openai-go.svg)](https://hysenlabs.com/projects/openai-openai-go)
Community notes

Community notes