You can build a Directus client in Go with the standard net/http package or evaluate a community Go SDK. Start by choosing REST or GraphQL, then design around your Directus instance’s actual collections, fields, permissions, and authentication policy. Directus documents both API styles as exposing the same core functionality; the practical choice is usually which interface best fits your callers and codebase.
Choose REST, GraphQL, or a Go SDK
Directus generates its API endpoints and GraphQL schema from the connected database architecture, and what a user can access depends on the installation’s permissions. Directus says REST and GraphQL map to the same core services and expose the same functionality, so this is primarily an ergonomics decision—not a documented difference in capability. See the Directus API reference.
| Option | Consider it when | Evaluate |
|---|---|---|
| REST | You need conventional collection operations and want to avoid embedding GraphQL query strings. | Whether its request and response shapes are convenient for your application. |
| GraphQL | The caller benefits from expressing the requested data shape in a query. | Query construction, response handling, and how queries fit your client’s interface. |
| Community Go SDK | You prefer a library over implementing transport and API operations yourself. | Compatibility with your Directus major version, endpoint coverage, maintenance, error behavior, authentication support, and dependency policy. |
| Custom Go client | You want to keep dependencies small or tailor the interface to your application. | The engineering cost of implementing and maintaining the operations you need. |
Directus documents a composable TypeScript SDK, but the sources reviewed do not establish an official Directus-maintained Go SDK. The community project altipla-consulting/directus-go describes itself as a Go SDK and claims its v2 line targets Directus 11, while v0/v1 target Directus 10. Those are the project’s compatibility claims, not an independent assessment of its maintenance or completeness. Check the repository and test the operations your application relies on before adopting it.
Build a small REST transport first
A useful first step is a thin transport layer that centralizes the base URL, request context, HTTP client, bearer token, and response handling. Keep collection-specific methods separate so your application does not depend on a universal schema that Directus does not promise.
#1 Best Overall
package directus
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"strings"
"time"
)
type Client struct {
baseURL string
token string
http *http.Client
}
func New(baseURL, token string) (*Client, error) {
baseURL = strings.TrimRight(baseURL, "/")
if baseURL == "" {
return nil, fmt.Errorf("directus base URL is required")
}
return &Client{
baseURL: baseURL,
token: token,
http: &http.Client{Timeout: 15 * time.Second},
}, nil
}
func (c *Client) do(ctx context.Context, method, path string, body []byte) ([]byte, error) {
req, err := http.NewRequestWithContext(
ctx,
method,
c.baseURL+"/"+strings.TrimLeft(path, "/"),
bytes.NewReader(body),
)
if err != nil {
return nil, fmt.Errorf("build Directus request: %w", err)
}
req.Header.Set("Accept", "application/json")
if len(body) > 0 {
req.Header.Set("Content-Type", "application/json")
}
if c.token != "" {
req.Header.Set("Authorization", "Bearer "+c.token)
}
resp, err := c.http.Do(req)
if err != nil {
return nil, fmt.Errorf("send Directus request: %w", err)
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("read Directus response: %w", err)
}
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
return nil, fmt.Errorf("Directus returned HTTP %s: %s", resp.Status, string(responseBody))
}
return responseBody, nil
}
The example uses a configurable base URL, a bounded HTTP timeout, a request context, bearer-header authentication when a token is configured, and response-body closure. It leaves error interpretation to callers: network/transport failures are wrapped separately from HTTP status failures. In production, consider whether response bodies can contain sensitive information before including them in errors or logs; redact them if needed. Add methods for the operations your application needs rather than turning this transport into a large collection of assumptions about Directus data.
Model the schema your instance actually exposes
Directus derives endpoints and the GraphQL schema from the connected database, while permissions affect available operations and returned data. A Go struct that assumes every Directus project has the same collections and fields is therefore unsafe as a general-purpose client design.
- For an application tied to one project, define explicit Go types for the collections and fields that application owns or consumes.
- For a reusable integration across unknown projects, provide generic decoding where appropriate, such as decoding JSON into
map[string]any, or let callers supply their own types. - Handle absent or inaccessible fields as possible outcomes rather than assuming every user can read every field.
- Keep project-specific collection names and request paths in configuration or application-level methods, not scattered through shared transport code.
Directus documents a server endpoint that returns the project’s OpenAPI specification. The specification is based on the current authenticated user’s read permissions, so it can help with schema inspection or code generation but should not be treated as a complete administrator-level inventory when retrieved with a less privileged account. See the Directus Server API reference.
Choose authentication for the integration
Directus states that “All data within the platform is private by default.” A project can configure a public role, or a client can authenticate to access private data. Directus documents temporary JWT access tokens returned by login, session tokens represented in cookies, and static user tokens. Temporary tokens are short-lived and paired with refresh tokens; static tokens do not expire and Directus describes them as less secure, though they can be useful for server-to-server communication. Details are in the Directus Authentication documentation.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #3
| Authentication choice | Fit | Important consideration |
|---|---|---|
| Public role | Only for data and operations deliberately made public by the project configuration. | Do not assume public access is enabled or appropriate for private data. |
| Static user token | Potentially convenient for a server-to-server integration when deployment policy allows it. | It does not expire and is described by Directus as less secure; protect and rotate it according to your organization’s policy. |
| Login and refresh | Applications that need temporary-token and refresh behavior. | Implement token lifecycle handling rather than treating an access token as permanent. |
| Cookie session | Applications designed around Directus session cookies. | Cross-domain cookie behavior depends on deployment configuration. |
Make authentication an explicit client configuration choice. For token-based requests, send the token in the Authorization: Bearer … header, keep secrets out of source control, and avoid logging credentials. Directus specifically warns that the access_token query parameter is not recommended in production because systems may log query parameters; do not place bearer credentials in URLs.
Separate transport failures from API failures
A maintainable client should let callers distinguish a request that failed to reach the server from a response that arrived with an unsuccessful HTTP status. If you later parse Directus error payloads, preserve useful status and error details without exposing tokens or sensitive data in logs. The small example returns status text and response content in its HTTP error; adapt that policy to your application’s privacy and observability requirements. The reviewed Directus sources do not prescribe a Go error type, so choose one that fits your callers and document what it retains.
Rank #4
- Use request contexts so callers can cancel work or set deadlines.
- Set a client timeout appropriate to the application, and allow it to be configured if operations have different latency needs.
- Close every response body, including responses with unsuccessful status codes.
- Keep response decoding and Directus-specific error parsing in a layer above raw HTTP transport.
Validate against the target project
Before relying on a client in production, test it against the Directus version, schema, and user permissions it will actually encounter. In particular, verify that its authentication flow works for the deployment, that expected collections and fields are visible to the chosen account, and that its error handling remains useful when a request is denied or otherwise unsuccessful. If you use generated models, retrieve the OpenAPI specification with an account whose permissions match the intended client; the result is permission-sensitive.
Quick Recap
Best Value
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Recommended Free Tools




