DEV Community

Cover image for I built an idiomatic Go SDK for the Hugging Face Inference API
E L N O R
E L N O R

Posted on • Originally published at Medium

I built an idiomatic Go SDK for the Hugging Face Inference API

TL;DR

huggingface-go is a lightweight, zero-dependency Go SDK for the Hugging Face Inference API. It covers chat completions and text embeddings today, with streaming, image generation, audio, and vision on the roadmap.

go get github.com/vastavikadi/huggingface-go
Enter fullscreen mode Exit fullscreen mode

Repo: github.com/vastavikadi/huggingface-go


The Problem

Go developers working with AI APIs are stuck writing boilerplate. Every Hugging Face call looks something like:

payload := map[string]interface{}{
    "model":    "meta-llama/Llama-3.1-8B-Instruct",
    "messages": []map[string]string{{"role": "user", "content": "Hello"}},
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api-inference.huggingface.co/v1/chat/completions", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
// ... unmarshal, check status, handle errors, repeat forever
Enter fullscreen mode Exit fullscreen mode

It works, but it's noisy, stringly-typed, and you have to reinvent it every project. Python got huggingface_hub.InferenceClient. Go deserved the same.


What huggingface-go gives you

✅ Typed client with functional options

import (
    "context"
    "fmt"
    "log"
    "os"

    huggingface "github.com/vastavikadi/huggingface-go"
)

func main() {
    client := huggingface.NewClient(
        huggingface.WithToken(os.Getenv("HF_TOKEN")),
    )

    resp, err := client.Chat.Completions.Create(
        context.Background(),
        huggingface.CreateChatCompletionRequest{
            Model: "openai/gpt-oss-120b",
            Messages: []huggingface.Message{
                {
                    Role:    huggingface.RoleUser,
                    Content: "Explain embeddings like I'm a Go developer.",
                },
            },
        },
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(resp.Choices[0].Message.Content)
}
Enter fullscreen mode Exit fullscreen mode

No map[string]interface{}. No magic strings for roles. The compiler catches your typos.


✅ Text Embeddings

embedding, err := client.Embed(
    context.Background(),
    huggingface.EmbedRequest{
        Model: "sentence-transformers/all-MiniLM-L6-v2",
        Input: "The quick brown fox",
    },
)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Vector dimensions: %d\n", len(embedding.Data))
Enter fullscreen mode Exit fullscreen mode

Plug this directly into a vector DB for semantic search or RAG pipelines.


✅ Context-aware everywhere

Every method accepts a context.Context as the first argument. This isn't optional ergonomics — it's how Go services propagate cancellation and deadlines. A 10-second timeout on your inference call is one line:

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

resp, err := client.Chat.Completions.Create(ctx, req)
Enter fullscreen mode Exit fullscreen mode

✅ Zero external dependencies

Check the go.mod. It's just the standard library. No indirect dependency surprises, no version conflicts, no supply chain surface area you didn't ask for.


Project structure

huggingface-go/
├── client.go            # NewClient + options wiring
├── options.go           # Functional options (WithToken, etc.)
├── transport.go         # HTTP layer
├── chat.go              # Chat namespace
├── chat_completions.go  # CreateChatCompletionRequest + Create()
├── chat_types.go        # Message, Role, ChatCompletionResponse
├── embedding.go         # Embed()
├── embedding_types.go   # EmbedRequest, EmbedResponse
└── examples/
    ├── example_chat.go
    ├── example_embeddings.go
    └── main.go
Enter fullscreen mode Exit fullscreen mode

Running the examples

git clone https://github.com/vastavikadi/huggingface-go
cd huggingface-go

export HF_TOKEN=your_token_here
go run ./examples
Enter fullscreen mode Exit fullscreen mode

Get a free token at huggingface.co/settings/tokens.


Roadmap

  • [x] Chat Completions
  • [x] Text Embeddings
  • [ ] Streaming (SSE)
  • [ ] Image Generation
  • [ ] Audio
  • [ ] Vision / Multimodal
  • [ ] Additional HF inference tasks

The next priority is streaming — most real chat UIs need it.


Contributing

Contributions are very welcome. The Go ecosystem needs more first-class AI tooling, and this project moves faster with community input.

# Fork, then:
git clone https://github.com/YOUR_USERNAME/huggingface-go
git checkout -b feature/streaming-support

# Make changes, add tests, then:
git push origin feature/streaming-support
# Open a PR 🎉
Enter fullscreen mode Exit fullscreen mode

Please follow standard Go conventions and add tests for new features. The goal is to match the feel of the standard library — if it doesn't feel like idiomatic Go, it's worth a discussion before merging.


Links

If you use it in a project, drop a comment — I'd love to see what you're building. And if something's missing or broken, open an issue.


Inspired by Python's huggingface_hub.InferenceClient and the Go community's taste for minimal, well-typed libraries.

Top comments (0)