The Go SDK Is Here
Here’s a complete Go app on Tako:
package main
import (
"net/http"
"tako.sh"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello from Tako"))
})
tako.ListenAndServe(mux)
}
That’s it. tako init, tako deploy, done. The tako.sh Go module is now available — Go joins JavaScript/TypeScript as a first-class Tako runtime.
One Interface: http.Handler
The JavaScript SDK is built around the fetch handler pattern — one function, every runtime. For Go, the equivalent is http.Handler. It’s the interface that every Go web framework already implements.
That means the integration is a single line:
// Gin
r := gin.Default()
tako.ListenAndServe(r)
// Echo
e := echo.New()
tako.ListenAndServe(e)
// Chi
r := chi.NewRouter()
tako.ListenAndServe(r)
No adapters. No wrappers. No glue code. If your framework implements http.Handler, it works. Gin, Echo, Chi, gorilla/mux, plain net/http — pass it to ListenAndServe and Tako handles the rest.
The one exception is Fiber, which uses fasthttp instead of net/http. For that, there’s tako.Listener() — it returns a net.Listener you hand directly to Fiber’s server.
Same Protocol, Same Guarantees
The Go SDK speaks the exact same Tako protocol as the JavaScript SDK. Everything we built the SDK for works identically:
| Concern | What the SDK does |
|---|---|
| Readiness | Signals TAKO:READY:<port> to stdout when the server is actually bound |
| Health checks | Intercepts Host: tako.internal with /status endpoint automatically |
| Secrets | Reads from fd 3 at init — before your code runs |
| Graceful shutdown | Catches SIGTERM/SIGINT, drains in-flight requests for 10 seconds |
| Metadata | tako.InstanceID(), tako.Version(), tako.Uptime() for observability |
The server doesn’t care whether the process behind the socket is Go, Bun, or Node. It just waits for TAKO:READY, probes /status, and routes traffic. One protocol, focused runtimes.
Type-Safe Secrets
Go’s approach to secrets leans into the type system. Run tako typegen and it generates a tako_secrets.go file with a typed struct:
// Generated by tako typegen — DO NOT EDIT.
var Secrets = struct {
DatabaseUrl func() string
ApiKey func() string
}{
DatabaseUrl: func() string { return tako.GetSecret("DATABASE_URL") },
ApiKey: func() string { return tako.GetSecret("API_KEY") },
}
Autocompletion in your editor. Compile-time errors if you typo a secret name. No more os.Getenv("DATABSE_URL") bugs that only surface in production.
Secrets come from one place: the fd 3 bootstrap envelope Tako hands to your process at startup. The same tako secret set … values work in tako dev and tako deploy, with no environment-variable ambiguity.
Channels
The Go SDK ships with the same channel primitive as the JavaScript SDK — channels for WebSocket/SSE communication:
tako.Channels.Register("chat", tako.ChannelDefinition{
ParamsSchema: []byte(`{
"type": "object",
"properties": { "roomId": { "type": "string" } },
"required": ["roomId"]
}`),
Auth: &tako.ChannelAuthScheme{HeaderName: "authorization"},
Verify: func(input tako.VerifyInput) tako.ChannelAuthDecision {
userID := authenticate(input.Header)
if userID != "" {
return tako.AllowChannel(tako.ChannelGrant{Subject: userID})
}
return tako.RejectChannel()
},
})
Typed params, per-channel auth callbacks, and transport selection are wired up through the same protocol the proxy already speaks. Clients connect to the exact channel name plus query params, for example /channels/chat?roomId=lobby.
Getting Started
mkdir my-app && cd my-app
tako init
Tako detects Go from go.mod, installs the tako.sh module, and scaffolds your project. Write your handlers, tako dev for local development with real HTTPS, tako deploy when you’re ready.
The full API is small on purpose — ListenAndServe, Listener, GetSecret, plus metadata and channel helpers. Check the docs for the complete reference, or browse the examples on GitHub to see Gin, Echo, Chi, and net/http in action.
Go is a language that values small interfaces and explicit control flow. We think tako.ListenAndServe(handler) fits right in.