sashabaranov/go-openai: an unofficial Go client for the OpenAI API
OpenAI, GPT 5.6, GPT-Image-2, Whisper API clients for Go
At a glance
- What is it?
- A Go client covering the Responses API, Chat Completions, images, audio, embeddings and legacy Assistants surfaces. It is small, stable, and maintained by the community rather than by OpenAI.
- Who is it for?
- Adopt it if you are writing Go services that call OpenAI or an OpenAI-compatible endpoint and you want a thin, Apache-2.0 client with streaming and error typing. Do not adopt it if you need OpenAI's own first-party SDK, or if you expect the client to hide the difference between Responses and Chat Completions; it deliberately exposes both.
- 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 last received commits 8 days ago.
- 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 28, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The gap this client fills for Go teams
Go has no first-party OpenAI SDK. Teams writing Go services either hand-roll HTTP calls against the REST API or pick a community client. This package is the latter: it wraps the OpenAI API in typed Go structs and methods, so a request is a struct literal rather than a map you assemble by hand.
The README is explicit that it is an unofficial client. It also states the scope: the Responses API is the recommended starting point for new text-generation, reasoning, tool-calling and multi-turn integrations, while Chat Completions remains available for existing integrations. Beyond those two, the client covers embeddings, images, audio, moderation, files, fine-tuning, batches, vector stores, and legacy Assistants API surfaces.
That breadth is the point. If you are building a Go backend that transcribes audio, generates an image, and runs a chat turn, you want one dependency and one error type rather than three ad hoc HTTP helpers. The repository layout confirms the split: audio.go, image.go, embeddings.go, fine_tunes.go, batch.go, assistant.go and response.go sit alongside chat.go and completion.go.
How the client is structured: config, client, typed requests
The architecture is conventional Go and easy to reason about. You build a Config, construct a Client from it, and call methods on that client. DefaultConfig takes an API key and returns a config you can mutate before construction. The README shows overriding BaseURL for an OpenAI-compatible endpoint, and mentions DefaultAzureConfig as the starting point for Azure OpenAI, where you configure the deployment mapping or API version your Azure resource requires.
Requests are structs. CreateResponseRequest carries Model, Instructions, Input, Store and PreviousResponseID. The Input field accepts either a plain string or a slice of typed input items, and the README notes that for reasoning, tools, multimodal output or custom processing you should inspect response.Output instead of the GetOutputText convenience method. That distinction matters: GetOutputText is a shortcut for the simple case, not a general accessor.
Errors are typed too. The README shows unwrapping with errors.As into *openai.APIError to read HTTPStatusCode, Code and Message. That is a real improvement over string matching on error text, and it is the pattern to use if you want retry logic keyed on status codes.
Model selection is deliberately not abstracted. The GPT-5.6 family is exposed as separate constants for capability, balance and efficiency tiers, and the README recommends picking the tier that matches the workload rather than using the flagship for every request. Model IDs are also accepted as plain strings, so you can call a model before a named constant exists in the package. That is a sensible escape hatch, and it also means typos in model IDs fail at the API rather than at compile time.
Installing it and making a first Responses call
Installation is a single go get. The module path matches the repository, and the README states the requirement: Go 1.18 or later. The go.mod in the repository confirms go 1.18 as the declared language version.
go get github.com/sashabaranov/go-openaiNext, export an API key. The README uses OPENAI_API_KEY as the environment variable name in its examples.
export OPENAI_API_KEY="<your key>"The quick start builds a client from that environment variable and creates a response. Note the model constant and the Instructions and Input fields; the README uses GPT5Dot6Sol here.
package main
import (
"context"
"fmt"
"log"
"os"
openai "github.com/sashabaranov/go-openai"
)
func main() {
client := openai.NewClient(os.Getenv("OPENAI_API_KEY"))
response, err := client.CreateResponse(context.Background(), openai.CreateResponseRequest{
Model: openai.GPT5Dot6Sol,
Instructions: "You are a concise technical explainer.",
Input: "Why is the sky blue?",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response.GetOutputText())
}Running that program prints the generated text. If you want to see a working multi-turn example rather than write one, the repository ships runnable examples under examples/, and the README gives the command form:
go run ./examples/responsesThe examples directory also contains completion, completion-with-tool, images and voice-to-text, so you can read the request shape for each surface before wiring it into your own service.
Multi-turn state and streaming, and where they get awkward
Conversation continuity is handled server-side. The README shows setting Store to true on the first request, then passing first.ID as PreviousResponseID on the second. The README adds a caveat worth reading twice: resend Instructions on each call when they should continue to apply. In other words, the client does not maintain a local message history for you in the Responses flow, and instructions are not sticky by default.
Streaming uses a channel-like receive loop. CreateResponseStream returns a stream you defer-close, then you call Recv in a loop, break on io.EOF, and handle events by type. The README filters on openai.ResponseStreamEventOutputTextDelta and prints event.Delta. Any other event type is your responsibility to handle or ignore, and the README does not enumerate the full event set.
That is the main ergonomic cost of this package. It is a faithful, typed mapping of the HTTP API rather than a framework. It will not buffer partial tool calls for you, it will not reconstruct a conversation, and it will not decide which event types matter. If your application needs an opinionated abstraction over streaming, you will write it yourself on top of Recv.
Where it is the wrong tool
Two cases stand out. First, if you want an SDK maintained by OpenAI itself, this is not it, and the README says so in its opening line. Support, release timing and API coverage decisions here come from the community.
Second, if you want a single obvious way to call a model, this package gives you two. Responses is recommended for new integrations, but Chat Completions remains supported and the README explicitly says to prefer Responses unless you specifically need the Chat Completions request or response shape. That is honest guidance, and it also means the library carries two request families with different semantics. A team without a convention will end up with both in the same codebase.
There is also the usual unofficial-client risk: the API can add a parameter before a typed field exists. The README anticipates this for models by noting that model IDs are accepted as strings. It does not describe an equivalent escape hatch for arbitrary request fields, and it does not document rollback or version pinning policy. The README does not document rollback.
Compared with the official openai-go SDK
The direct alternative is OpenAI's own Go SDK, commonly referred to as openai-go. The difference is not features so much as ownership and design intent.
The official SDK is maintained by the API vendor, so its release cadence tracks API changes and its types are generated from the vendor's own specification. This package is a hand-written community client that has accumulated surfaces over time, including legacy ones such as the Assistants API, edits and engines files that remain in the repository tree. That accumulation is useful if you still call older endpoints, and it is dead weight if you do not.
The practical difference shows up in the small things. This package exposes DefaultAzureConfig for Azure OpenAI and a documented BaseURL override for compatible endpoints, which is convenient for self-hosted or proxy setups. It also lets you pass a model ID as a string before a constant exists, which the official SDK's generated types generally do not encourage. In exchange, you accept community maintenance and community review of new API surfaces. Neither choice is wrong; they are different bets about who should own the client.
Licence, maintenance and the cost of upgrading
The repository is licensed Apache-2.0, which permits commercial use and modification and includes an explicit patent grant. It also requires that you preserve notices and state changes. That is a permissive licence, but it is not the MIT licence, and if your organisation maintains an allowlist of approved licences, Apache-2.0 needs to be on it. This is a description of the licence text, not legal advice.
The last push was on 2026-09-11, and the most recent tagged release, v1.42.1, was published the same day. Before that, v1.42.0 was tagged on 2026-08-02 and v1.41.2 on 2025-09-12. The gap between v1.41.2 and v1.42.0 is roughly eleven months, which is worth knowing if you are planning around release cadence: the project does not ship tags on a fixed schedule.
Upgrade cost is dominated by API surface changes rather than the client itself. Moving from Chat Completions to Responses is a rewrite of your request construction and your response parsing, not a version bump, and the README frames it as a migration rather than a toggle. Pin a tagged version in go.mod, read the release notes for the tag you are moving to, and check that the model constants you reference exist in that tag before you upgrade.
Editorial conclusion
Adopt it if you are writing Go services that call OpenAI or an OpenAI-compatible endpoint and you want a thin, Apache-2.0 client with streaming and error typing. Do not adopt it if you need OpenAI's own first-party SDK, or if you expect the client to hide the difference between Responses and Chat Completions; it deliberately exposes both. Before committing, verify that the model constants you need exist in the tagged version you pin, and confirm whether your workload requires Responses or the older Chat Completions shape.
Frequently asked questions
What is the difference between ChatGPT and OpenAI?
ChatGPT is the consumer product, while OpenAI is the company whose API this Go client calls. The README describes sashabaranov/go-openai as an unofficial Go client for the OpenAI API, not as a client for the ChatGPT application.
Is sashabaranov/go-openai compatible with OpenAI-compatible endpoints?
Yes. The README shows setting config.BaseURL to a compatible endpoint and constructing the client with NewClientWithConfig, so any service that speaks the same request shape can be targeted.
How do I install sashabaranov/go-openai?
Run go get github.com/sashabaranov/go-openai. The README states the package requires Go 1.18 or later, and the repository's go.mod declares go 1.18.
Which API should I use with sashabaranov/go-openai, Responses or Chat Completions?
The README recommends starting with the Responses API for new text-generation, reasoning, tool-calling and multi-turn integrations, and says to prefer it unless you specifically need the Chat Completions request or response shape.
How does sashabaranov/go-openai handle errors?
API failures can be unwrapped with errors.As into *openai.APIError, which exposes HTTPStatusCode, Code and Message. The README shows this pattern directly.
Official sources
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.
[](https://hysenlabs.com/projects/sashabaranov-go-openai)