godo, the Go client where each DigitalOcean resource is its own file
DigitalOcean Go API client
At a glance
- What is it?
- godo is the Go client library for the DigitalOcean V2 API, and its shape follows the API: one file per resource, one service tree per area, and a client that now also carries inference and Action Gateway calls. The trade is a client that tracks the platform closely and a token model with two credential classes you have to understand.
- Who is it for?
- godo fits a Go team that automates DigitalOcean from code, whether that means creating droplets, running Kubernetes clusters, or wiring an agent into the Action Gateway, because the library gives typed request and response structs for each area instead of hand written HTTP calls.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 2 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 November 7, 2026, and from our analysis. They are not legal advice.
Star history
- digitalocean/godo1,548 ★ · +2
| Repository | 2026-10-16 | 2026-11-07 |
|---|---|---|
| digitalocean/godo | 1.5k | 1.5k |
2 Stars in the last 22 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The directory listing is the API surface
The most honest description of godo is its own file list. Every DigitalOcean resource has a file of its own, and nearly every one of those files has a matching test file next to it. There are droplets.go and droplet_actions.go and droplet_autoscale.go, databases.go, cdn.go, domains.go, certificates.go, account.go, balance.go, billing_history.go, byoip_prefixes.go, apps.go with a generated companion apps.gen.go, action.go, agentplatform.go, and a family of action_gateway files split by concern into tools, toolbelts, resources, runtime, sessions, connections and users. The result is that a developer can look up where the Kubernetes client lives, or the databases client, by reading the file list instead of reading documentation. The consequence of that layout is a library with a very wide surface and a very small amount of shared abstraction, which is why the rest of the design matters more than the file count.
One client object, one service tree per area
A single client carries every service, and you reach the API through the tree hanging off it. The construction is deliberately minimal.
package main
import (
"github.com/digitalocean/godo"
)
func main() {
client := godo.NewFromToken("my-digitalocean-api-token")
}From there, client.Droplets.Create, client.Kubernetes, client.Volumes, client.Models, client.Chat and client.ActionGateway are the entry points, and the services are typed rather than generic, which is what makes the library worth having over a hand rolled HTTP client. One documented detail is easy to miss. If you need to pass a context.Context into the client itself, you construct it manually with godo.NewClient instead of the token helper, so the context is available to the HTTP layer rather than being created later per call. The client also carries retry behaviour, since hashicorp/go-retryablehttp is a direct dependency, and query parameters are encoded with google/go-querystring, which is how the list options work.
Two credential classes, and a 401 that explains itself
The authentication section is unusually explicit about a trap, and it is worth reading before you write the code. The credential you pass to godo.NewFromToken matters more than which API you call. Infrastructure calls, the ones covering Droplets, Kubernetes and Volumes among others, need a DigitalOcean API token, a personal access token, managed from the Applications page of the control panel. Inference calls, covering Chat, Models, Embeddings, ImageGenerations, Messages, Responses and BatchInference, need either a PAT created with full access scope or a model access key.
client := godo.NewFromToken(os.Getenv("DIGITALOCEAN_TOKEN"))
client := godo.NewFromToken(os.Getenv("MODEL_ACCESS_KEY"))Both lines construct the same client. The consequence of getting it wrong is precise: with a limited scope PAT, infrastructure calls work and inference calls fail with a 401. The remedy is stated too, create a PAT with full access or use a model access key. The Action Gateway carries the same pattern, since it needs a PAT with the matching action_gateway scopes. A library where one constructor accepts two credential classes and the failure mode is a 401 on a subset of endpoints is a good argument for keeping the client behind your own thin interface in application code.
Installing it and creating your first Droplet
Installation is a single go get, and the pinned form is the one to use in an application.
go get github.com/digitalocean/[email protected]The unversioned form is documented for non module usage or for taking the latest version.
go get github.com/digitalocean/godoThe first real call is a Droplet creation, and the request struct shows the level of detail the library exposes.
dropletName := "super-cool-droplet"
createRequest := &godo.DropletCreateRequest{
Name: dropletName,
Region: "nyc3",
Size: "s-1vcpu-1gb",
Image: godo.DropletCreateImage{
Slug: "ubuntu-20-04-x64",
},
}
ctx := context.TODO()
newDroplet, _, err := client.Droplets.Create(ctx, createRequest)Note the return signature. Every call returns the value, a response object and an error, and the response object is where pagination links and rate limit headers live, which is the reason the error check in the example is a three part return rather than a plain error. The image is given as a struct with a Slug field, and the region and size are string identifiers, so the library does not wrap the platform's catalog of regions and sizes in typed enums.
Pagination is your loop, not the library's
List endpoints are paginated, and the documented pattern is to request pages yourself using a list options struct. The example walks the Droplets list until the last page.
func DropletList(ctx context.Context, client *godo.Client) ([]godo.Droplet, error) {
list := []godo.Droplet{}
opt := &godo.ListOptions{}
for {
droplets, resp, err := client.Droplets.List(ctx, opt)
if err != nil {
return nil, err
}
list = append(list, droplets...)The response returned alongside the items carries the information needed to advance to the next page, and the loop terminates when that information says there is no further page. This is the design you would expect from a library that mirrors the API rather than one that hides it, and it has one practical consequence worth planning for. A list of every resource on an account is an unbounded amount of work, so a job that enumerates droplets should page deliberately and handle the case where the account grows between pages, rather than assuming a single request returns everything.
Action Gateway sessions, tool discovery and a policy default
The newest area of the client is the Action Gateway, a control plane for tools, toolbelts, output views, MCP servers, connections, sessions, users and end-user limits, and it is where the library's most interesting behaviour sits. A session is created for an actor, and the flow is to create a runtime session, ask it for its tools, call a chat completion with those tools attached, and hand the tool calls back to the session for handling.
toolbelts, _, err := client.ActionGateway.Toolbelts.List(ctx, &godo.ActionGatewayToolbeltsListOptions{Status: "active"})
session, _, err := client.ActionGateway.Sessions.CreateRuntime(ctx, &godo.ActionGatewaySessionCreateRequest{
ActorID: "alice",
})
tools, _, err := session.ChatTools(ctx, nil)Three details in the documentation change how you should write this. The session exposes direct tool discovery and invocation through session.Tools, while session.Code runs sandboxed code, and the other inference formats have their own MessageTools and ResponseTools equivalents. CreateRuntime defaults to an ask-before-executing policy, so an agent will not silently run a tool unless you pass an explicit policy. And the Tools field is nil-sensitive: omitting it enables all tools, while an empty non-nil slice enables none, which is a sharp edge worth a comment in your own code. MCP calls are restricted to HTTPS session URLs on actions.do-ai.run, with WithActionGatewayMCPBaseURL available to override the origin for development or tests.
Serverless inference and the model catalog
The inference side of the client talks to the Serverless Inference API at inference.do-ai.run, and the same client object serves it. A chat completion takes a model identifier and a message list, with a helper for the user role.
completion, _, err := client.Chat.Completions.New(ctx, &godo.ChatCompletionNewParams{
Model: "llama3.3-70b-instruct",
Messages: []godo.ChatCompletionMessage{
godo.UserMessage("Write me a haiku"),
},
})Listing models follows the same shape as any other list, returning a page with a data slice.
page, _, err := client.Models.List(ctx)
for _, m := range page.Data {
fmt.Println(m.ID)
}Image generation is a separate service with its own parameter struct, taking a model, a prompt and a count.
image, _, err := client.ImageGenerations.Generate(ctx, &godo.ImageGenerateParams{
Model: "stable-diffusion-3.5-large",
Prompt: "A friendly cartoon shark typing on a laptop at a sunny beach",
N: 1,
})The repository also carries example directories for serverless inference, agent inference, agent platform, hosted agents and insights, so the streaming, embedding, message, response, async and batch variants are demonstrated somewhere even where the main documentation only shows the simplest calls.
Release mechanics, retracted versions and the licence question
godo is a client for a platform that ships new products often, and the release process is automated in the Makefile. The version string is read out of the source rather than duplicated, the bump type is a make variable, and a changes target runs github-changelog-generator over the merged pull requests since the last release.
make BUMP=(bugfix|feature|breaking) bump_versionThe go.mod declares go 1.23.0 and pins a small dependency set, and it also carries a retract block, which lists v1.165.0 and v1.164.0 as versions that should not be used, with a comment that it contains a retagging issue. That is a signal worth noticing: a module that gets published often enough to hit a tagging mistake will occasionally publish a bad version, and the retract directive is how the Go toolchain tells users to move past it. The tags themselves show the cadence, with v1.223.0, v1.224.0 and v1.225.0 published within days of each other in October 2026, and the last push on 2026-10-19, so the library moves at the speed of the API it wraps. The licence is the one item that needs attention rather than trust: the repository carries a LICENSE.txt that GitHub could not classify, so its terms are in a custom document. Nothing here is legal advice, but a company that runs a licence scanner over its dependencies will not get an answer for this package until somebody reads that file.
Editorial conclusion
godo fits a Go team that automates DigitalOcean from code, whether that means creating droplets, running Kubernetes clusters, or wiring an agent into the Action Gateway, because the library gives typed request and response structs for each area instead of hand written HTTP calls. It does not fit a team whose only need is a one-off script against the API from another language, where the extra dependency is more than the problem, and it does not fit a caller that intends to use the inference endpoints with a limited scope token, because those calls will fail with a 401. Verify three things before you build on it: that the credential you hold is the right class for the endpoints you plan to call, that the version you pin contains the service tree you need, since the library ships releases almost daily, and what the custom LICENSE.txt permits, because GitHub could not classify it.
Frequently asked questions
How do I install the godo Go client?
Use go get github.com/digitalocean/[email protected] with the version you want, or the unversioned form for the latest version or for non module usage. The module path is github.com/digitalocean/godo and it declares go 1.23.0.
Which credentials does godo need for inference endpoints?
Infrastructure calls need a DigitalOcean API token, while inference calls such as Chat, Models, Embeddings and ImageGenerations need a PAT with full access scope or a model access key. With a limited scope PAT, infrastructure calls work and inference calls fail with a 401.
Does godo handle pagination for me?
No. The documented pattern is to request pages individually with a ListOptions struct and loop until the response indicates the last page. The examples directory shows the pattern for listing Droplets.
What is the Action Gateway in godo?
It is a control plane exposed as client.ActionGateway, covering tools, toolbelts, output views, MCP servers, connections, sessions, users and end-user limits, and it needs a PAT with the matching action_gateway scopes. Sessions created with CreateRuntime default to an ask-before-executing policy.
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/digitalocean-godo)Star history chart for your README
[](https://hysenlabs.com/projects/digitalocean-godo)Was this useful?