---
title: "Use MainSDK from Go"
description: "Add the native MainSDK Go module to a service, store data and files as one owner, and return problem details from net/http."
section: "guides"
status: "Planned for 1.5"
spec: "go-sdk"
canonical: "https://mainsdk.dev/docs/guides/use-mainsdk-from-go"
updated: "2026-10-28"
---

# Use MainSDK from Go

> Add the native MainSDK Go module to a service, store data and files as one owner, and return problem details from net/http.

Status: Planned for 1.5 · Canonical: https://mainsdk.dev/docs/guides/use-mainsdk-from-go · Updated: 2026-10-28

You will add the `mainsdk.dev/go` module, run it on its local drivers, and wrap a handler. It takes about 10 minutes. The module is native, standard library only, no cgo. It shares no code with the TypeScript SDK, only `main.yaml`, the error codes and the wire formats.

## You need

- Go 1.22 or later and a `main.yaml` with `schema: 1` (`npx mainsdk init` writes one).
- The module is pre-release and not tagged. Use a `replace` directive to `packages/go` in the MainSDK repository until it is.

## 1. Call an interface

`context.Context` carries cancellation, the deadline, the tenant and the trace.

```go title="main.go"
app, err := mainsdk.Load(ctx)
if err != nil {
	return err
}
ctx = mainsdk.WithTenant(ctx, "tnt_a")
ref, err := app.Files().Upload(ctx, []byte("hello"), files.Owner("u1"), files.Label("pii"))
rows, err := app.DB().Model("orders").For("u1").List(ctx)
```

A call that needs a tenant and has none returns `MAIN-TENANT-0001`. In tests use `mainsdk.NewTestApp()`, which keeps everything in memory.

## 2. Return problem details from net/http

```go title="server.go"
http.Handle("/orders", mainsdk.Middleware(func(w http.ResponseWriter, r *http.Request) error {
	// return a *mainsdk.Error, or any error
	return nil
}))
```

The middleware reads `traceparent` and `X-Tenant-Id`, puts them on the request context, and renders a returned error as `application/problem+json` with its `code` and `fix`. An error that is not a `*mainsdk.Error` returns a 500 with the message hidden.

## 3. Check the project

`npx mainsdk check` runs golangci-lint (`MAIN-GO-0001`), gosec (`MAIN-GO-0002`) and govulncheck (`MAIN-GO-0003`) with the usual gates. A missing tool is a warning, `MAIN-GO-0004`, never a pass. Run `go vet ./...` and `go test ./...` too.

## Next

- Go agents load the `mainsdk-go` skill.
- Run the parity vectors against your build: `mainsdk conformance run --impl "go run ./cmd/conformance" --json`.
