Library / SDK
cloudflare/cloudflare-go avatar
cloudflare/cloudflare-go

cloudflare-go v7: the Stainless-generated Go SDK for the Cloudflare API

The official Go library for the Cloudflare API

2,099 stars778 forksGoApache-2.0

At a glance

What is it?
cloudflare-go v7 is the official Go client for the Cloudflare REST API, generated by Stainless and requiring Go 1.22 or later. Its Field type prevents accidental zero-value sends, and it publishes releases alongside the older v0 hand-written track with no documented migration path between them.
Who is it for?
cloudflare-go v7 suits Go projects that call the Cloudflare API and want a generated client rather than a manually maintained HTTP wrapper. The Field-based request model and the JSON sidecar on responses cover genuinely awkward Go edge cases around optional fields.
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 10 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 October 6, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Generated by Stainless from the Cloudflare API schema

cloudflare-go v7 is the official Go client library for the Cloudflare REST API. Unlike earlier versions of this library, v7 is generated by Stainless rather than hand-written by the Cloudflare team. The generation source is the Cloudflare API schema, and the full API surface the SDK covers is documented in api.md at the repository root. The README points to that file rather than listing every resource and method inline, which means api.md is the reference to check for whether a specific Cloudflare service is covered.

Go 1.22 is the minimum version, as the go.mod constraint specifies. Dependencies are minimal: gjson v1.14.4 and sjson v1.2.5 handle the JSON manipulation layer, with match v1.1.1 and pretty v1.2.1 pulled in as indirect dependencies from the same author. There is no compiled extension and nothing to build before importing.

Being Stainless-generated has a practical consequence for contributors. The Go source code is not the primary artifact; the API schema is. Changes to generated Go code that the generator would overwrite on the next generation pass are not preserved. Contributions targeting API behavior go upstream to Cloudflare's API schema, not to this repository's Go files directly. For users, this means the SDK surface changes when Cloudflare updates the schema, and a version bump may add or alter methods in ways that do not come from traditional code review in this repository.

Install v7.12.0 and create your first zone from Go code

Pin the current release or import the major version path and let the module system resolve it:

sh
go get -u 'github.com/cloudflare/cloudflare-go/[email protected]'

Alternatively, import the v7 path without a version suffix:

go
import (
	"github.com/cloudflare/cloudflare-go/v7" // imported as cloudflare
)

The README's first usage example creates a Cloudflare zone. The client reads the `CLOUDFLARE_API_TOKEN` environment variable by default; `option.WithAPIToken` overrides it explicitly:

go
client := cloudflare.NewClient(
	option.WithAPIToken("Sn3lZJTBX6kkg7OdcBUAxOO963GEIyGQqnFTOFYY"),
)
zone, err := client.Zones.New(context.TODO(), zones.ZoneNewParams{
	Account: cloudflare.F(zones.ZoneNewParamsAccount{
		ID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"),
	}),
	Name: cloudflare.F("example.com"),
	Type: cloudflare.F(zones.TypeFull),
})

Every field on `zones.ZoneNewParams` is wrapped in the `cloudflare.F` helper. That is the library's core request model, appearing on every request parameter throughout the SDK. The successful return value is a zone object; `zone.ID` holds the assigned zone identifier. Errors are returned as the second value and should be checked before using the zone.

The Field type keeps zero values from being sent unintentionally

All request parameters use the generic `Field` type. Go's zero value for a string, integer, or bool is indistinguishable from an unset field when serializing to JSON, which means a missing required parameter can silently send as an empty string or a zero integer. With the `Field` wrapper, any field not explicitly set is omitted from the request body entirely rather than serialized as its zero value.

Four helpers construct field values. `F[T]()` is the generic form for any value type. `String()`, `Int()`, and `Float()` are shortcuts for common primitives. For an explicit null, use `Null[T]()`. When the API specifies one type but you need to send something the type checker would not allow, `Raw[T](any)` bypasses the constraint and lets you send a float where the API declares int64, for example.

go
params := FooParams{
	Name: cloudflare.F("hello"),
	Description: cloudflare.Null[string](),
}

This design catches a category of API bugs at compile time rather than at runtime, which is the main reason the library chose the wrapper model over plain struct literals. The cost is in readability: in a large request struct, the wrapping calls occupy more horizontal space than the values themselves. An optional string that the caller simply omits sends nothing to the API, rather than an empty string that some API endpoints treat differently from the field being absent.

Response structs hold value types, and the JSON field distinguishes null from absent

All fields in response structs are value types rather than pointers or option wrappers. If the API returns null for a field, omits it, or returns a value that cannot be coerced to the expected Go type, the corresponding struct field holds its zero value. Three semantically different states all map to the same Go representation, so the SDK attaches a `JSON` field to each response struct with per-property metadata.

go
if res.Name == "" {
	// true if `"name"` is either not present or explicitly null
	res.JSON.Name.IsNull()

	// true if the `"name"` key was not present in the response JSON at all
	res.JSON.Name.IsMissing()
}

For properties that came back in a format the SDK could not coerce:

go
if res.JSON.Name.IsInvalid() {
	raw := res.JSON.Name.Raw()
}

The `JSON` struct also carries an `Extras` map containing any properties in the response JSON that the SDK does not model. A Cloudflare API feature added after the SDK version you depend on will appear there as a raw JSON string, accessible without upgrading the SDK. That is a safety valve for API drift, but the data comes back untyped. How useful `Extras` is in practice depends on how often the live API outpaces the SDK's model of it.

ListAutoPaging handles page boundaries, but each boundary is a network request

Paginated endpoints expose two access patterns. `ListAutoPaging()` iterates through all items across all pages:

go
iter := client.Accounts.ListAutoPaging(context.TODO(), accounts.AccountListParams{})
for iter.Next() {
	account := iter.Current()
	fmt.Printf("%+v\n", account)
}
if err := iter.Err(); err != nil {
	panic(err.Error())
}

Each call to `iter.Next()` fires a network request when the current page is exhausted, so the iterator is not a local in-memory operation. A list that spans thousands of accounts will issue many sequential HTTP calls, and each one is subject to the request timeout and retry policy in effect.

`List()` returns a single page and a response object with `GetNextPage()` for callers that want to control pagination manually. The choice between the two depends on whether you want the SDK to manage cursor tracking or whether your application has its own page-by-page logic.

Neither the pagination documentation nor the README describes a rate-limit handler or a backoff strategy built into the iterator. Callers working with large account inventories have to layer that above the SDK themselves, using the per-request options or wrapping the iterator.

Errors wrap the full HTTP context, and timeouts must be set via context

When the Cloudflare API returns a non-2xx status, the SDK returns a `*cloudflare.Error`. This error type carries the `StatusCode`, a pointer to `*http.Request`, and a pointer to `*http.Response`, as well as the parsed error body. Inspect it with the standard `errors.As` pattern:

go
var apierr *cloudflare.Error
if errors.As(err, &apierr) {
	println(string(apierr.DumpRequest(true)))
	println(string(apierr.DumpResponse(true)))
}

Transport-level failures return unwrapped, so a failed TCP connection returns a `*url.Error` wrapping a `*net.OpError` rather than a `*cloudflare.Error`. Code that handles errors needs to check for both types.

Setting a timeout is opt-in; the SDK imposes none by default. Use context to configure a deadline for a request lifecycle, for example with `context.WithTimeout`. One behavior is worth calling out: when the SDK retries a failed request, the context deadline does not reset from zero. A context carrying a 5-minute deadline covers the full retry sequence, not each individual attempt. To set a per-retry timeout separately, use `option.WithRequestTimeout()`, which is described in the full list of request options at pkg.go.dev.

Two active release tracks with no documented path from v0 to v7

The repository publishes on two version tracks simultaneously. v7.12.0 landed on October 1, 2026, and v0.119.0 landed on September 25, 2026. These are not minor variants of the same SDK: v7 is the Stainless-generated client described throughout this article, while v0 is the earlier hand-written library that predates the Stainless generation.

A Go project importing from `github.com/cloudflare/cloudflare-go` without a major version suffix is using v0. The Field-based request model, the JSON sidecar on response structs, the functional `RequestOption` closure pattern, and the `ListAutoPaging` iterator are all design choices introduced in v7. The repository holds CHANGELOG.md alongside CHANGELOG-v7.2.0.md, reflecting the split history.

There is no migration guide in the repository. Any project moving from v0 to v7 has to audit its request construction, error handling, and pagination code, because the two client APIs differ throughout. The Apache-2.0 licence applies to both tracks. CONTRIBUTING.md and SECURITY.md are both present at the repository root. A CHANGELOG.md covers the v0 history, and a separate CHANGELOG-v7.2.0.md covers the v7 history from that release onward, so reading the right file depends on which track you are on.

Editorial conclusion

cloudflare-go v7 suits Go projects that call the Cloudflare API and want a generated client rather than a manually maintained HTTP wrapper. The Field-based request model and the JSON sidecar on responses cover genuinely awkward Go edge cases around optional fields. The tradeoff is verbosity: wrapping every parameter in F() and reading from the JSON sidecar adds noise to both request construction and response handling. Skip v7 if you are already on v0.119.0 and the endpoints you need work there; the two tracks are not API-compatible and no migration guide exists. Before adopting v7, confirm that the endpoints you need appear in api.md.

Frequently asked questions

What is cloudflare-go?

cloudflare-go is the official Go client library for the Cloudflare REST API. Version 7 is generated by Stainless and requires Go 1.22 or later. The full API surface it covers is documented in api.md at the repository root.

How do I install cloudflare-go v7?

Run `go get -u 'github.com/cloudflare/cloudflare-go/[email protected]'` to pin the current release, or import `github.com/cloudflare/cloudflare-go/v7` in your Go source and let the module system fetch it. Go 1.22 or later is required.

What is the difference between cloudflare-go v0 and v7?

v7 is generated by Stainless and uses a Field type for all request parameters, a JSON sidecar for response metadata, and a functional RequestOption pattern. v0 is the earlier hand-written client with a different API surface. The repository has no documented migration path between them.

How does cloudflare-go handle pagination?

Paginated endpoints expose ListAutoPaging(), which iterates through all pages automatically with each page boundary firing a network request, and List() with GetNextPage() for callers that want manual control over page fetching.

How do I set a timeout with cloudflare-go?

Pass a context with a deadline, such as one from context.WithTimeout(), to the request. Requests have no built-in timeout. The context deadline covers the full retry sequence, so use option.WithRequestTimeout() for a per-retry limit.

Official sources

  1. cloudflare/cloudflare-go on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
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/cloudflare-cloudflare-go.svg)](https://hysenlabs.com/projects/cloudflare-cloudflare-go)