Putnami
DocsGitHub

Licensed under FSL-1.1-MIT

Getting Started
Concepts
How To
Build A Web App
Build An Api Service
Share Code Between Projects
Configure Your App
Add Persistence
Add Authentication
Add Background Jobs
Principles
Tooling & Workspace
Workspace Overview
Cli
Jobs & Commands
SDK
Error Handling
Extensions
Typescript
Go
Python
Docker
Ci
Frameworks
Typescript
OverviewWebReact RoutingForms And ActionsStatic FilesApiErrors And ResponsesConfigurationLoggingHttp And MiddlewareDependency InjectionPlugins And LifecycleSessionsAuthPersistenceEventsStorageCachingWebsocketsTestingHealth ChecksTelemetryProto GrpcSmart Client
Go
OverviewHttpDependency InjectionPlugins And LifecycleConfigurationSecurityPersistenceErrorsEventsStorageCachingLoggingTelemetryGrpcService ClientsValidationOpenapiTesting
Platform
  1. DocsSeparator
  2. FrameworksSeparator
  3. GoSeparator
  4. Overview

Go Framework

The Putnami Go framework follows the same Putnami architecture in idiomatic Go. It provides the same core abstractions — dependency injection, HTTP server, security, events, storage, and service clients — using Go's strengths: goroutines, channels, generics, context.Context, and interfaces.

Installation

All Go packages use the go.putnami.dev vanity import domain. The go.putnami.dev host serves go-import meta tags that redirect go get to the source repository.

go get go.putnami.dev/app
go get go.putnami.dev/http
go get go.putnami.dev/inject

Package overview

Package Description
inject Hierarchical DI container with named tokens, generics, scoped providers, cycle detection
config Multi-source configuration (YAML, env vars, maps) with struct tags and DI bridge
logger Structured logging via slog with pluggable sinks (JSON default, console, buffer, memory)
schema Struct-tag-based validation with type coercion
errors Structured error model with typed codes, categories, stack capture, HTTP mapping
app Plugin-based application lifecycle with module composition and optional fx-style DI
http HTTP server, trie-based router, middleware (recovery, logging, rate limiting, compression)
security Declarative authorization middleware (roles, scopes, custom guards)
grpc gRPC server with Connect protocol gateway and DI-scoped requests
openapi OpenAPI 3.0.3 spec generation from Go struct types
sql PostgreSQL via pgx — connection pool, repository pattern, migrations, query builder
cache Layered caching (memory + disk) with TTL and FIFO eviction
telemetry OpenTelemetry integration for distributed tracing and metrics
events Typed event system with topics, handlers, retry, and dead-letter queues
storage Object storage with pluggable backends (memory, filesystem, S3)
client Service client builder with retry, circuit breaker, and interceptor chain

Quick start

Explicit wiring (idiomatic Go)

package main

import (
    "context"

    "go.putnami.dev/app"
    "go.putnami.dev/config"
    fhttp "go.putnami.dev/http"
)

type AppConfig struct {
    Port int    `json:"port" default:"8080" env:"PORT"`
    DSN  string `json:"dsn" env:"DATABASE_URL"`
}

func main() {
    cfg, _ := config.Load(config.Config[AppConfig]("app"))
    db := connectDB(cfg.DSN)
    users := NewUserService(db)

    server := fhttp.NewServerPlugin(fhttp.ServerConfig{Port: cfg.Port})
    server.Use(fhttp.Recovery())
    server.GET("/users", listUsersHandler(users))

    a := app.New("my-service")
    a.Module.Use(server)
    a.Run(func(ctx context.Context) error {
        <-ctx.Done()
        return nil
    })
    a.ListenAndServe()
}

Constructor-based DI (fx-style)

func main() {
    a := app.New("my-service")
    a.ProvideFunc(
        LoadConfig,
        connectDB,
        NewUserService,
        newHTTPServer,
    )
    a.InvokeFunc(func(server *fhttp.ServerPlugin, users *UserService) {
        server.GET("/users", listUsersHandler(users))
    })
    a.ListenAndServe()
}

Both approaches can be mixed freely. DI is entirely optional — applications that register no providers skip container creation entirely.

Architecture

The framework is organized into four layers:

Foundation:      errors, logger, config, schema
DI:              inject (optional, standalone)
Application:     app → http, grpc, sql, events, storage, cache, client
Cross-cutting:   security, telemetry, openapi

Every component is a plugin that participates in the application lifecycle. Plugins compose into modules, and modules form a tree rooted at the application. See Plugins & Lifecycle for details.

Design principles

  • Stdlib only — no external runtime dependencies (except pgx for PostgreSQL and gRPC)
  • Optional DI — wire services explicitly or use constructor-based DI; both compose naturally
  • Generics — type-safe topics, repositories, caches, and tokens via Go 1.18+ generics
  • Context-driven — transactions, scopes, loggers, and traces all flow through context.Context
  • Plugin architecture — every framework component implements the same lifecycle interface
  • Goroutine-safe — shared state uses sync.Mutex, channels, or atomics

TypeScript ↔ Go comparison

Concept TypeScript Go
DI tokens named<T>('key') inject.Named[T]("key")
DI scope AsyncLocalStorage context.Context
Event topics topic('name', schema) events.NewTopic[T]("name")
Event handlers handler(topic).handle(fn) events.Handle(topic, fn, opts...)
Storage buckets Bucket('name', opts) storage.Bucket("name", opts...)
Client builder ClientBuilder.for(Client) client.NewBuilder()
Circuit breaker Custom implementation client.CircuitBreaker
Config Config('name', schema) config.Config[T]("name")
Validation Schema DSL Struct tags
Application application().use(plugin) app.New("name").Module.Use(plugin)

Related documentation

  • HTTP & Middleware
  • Dependency Injection
  • Plugins & Lifecycle
  • TypeScript framework

On this page

  • Go Framework
  • Installation
  • Package overview
  • Quick start
  • Explicit wiring (idiomatic Go)
  • Constructor-based DI (fx-style)
  • Architecture
  • Design principles
  • TypeScript ↔ Go comparison
  • Related documentation