GoFr: an opinionated Go framework that ships observability and datasources with the service
An opinionated GoLang framework for accelerated microservice development. Built in support for databases and observability.
At a glance
- What is it?
- GoFr is an Apache-2.0 Go microservice framework whose core claim is that logging, tracing, metrics, health checks and database wiring should arrive with the app rather than be assembled by hand. This review covers what that buys you, what it costs, and where the documentation stops.
- Who is it for?
- Adopt GoFr if you are starting a Kubernetes-deployed Go service and want traces, metrics and datasource health without writing that plumbing yourself, and if the opinionated shape of gofr.Context suits your team. Do not adopt it if you want to keep gorilla/mux or chi routing at the centre of your design, or if you need a migration path off the framework later, because the datasource and context types are GoFr's own.
- 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 received new commits within the last day.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem GoFr picks for you
A Go microservice starts as an HTTP handler and becomes a small platform. You add a logger, then a request ID, then OpenTelemetry, then a Prometheus endpoint, then health checks per datasource, then a circuit breaker around the outbound call, then a migration runner. None of that is the product you were asked to build.
GoFr's answer is to make those decisions once, in the framework, and hand you a smaller surface. The README describes the project as "An Opinionated Microservice Development Framework" and states that its focus is Kubernetes deployment and out-of-the-box observability, with microservices at the core. The audience follows from that: teams running several Go services on Kubernetes who would rather accept a house style than maintain their own internal framework. If you are writing a single binary with one route and no datasources, the framework's defaults are more machinery than the job needs.
How GoFr wires a service: one context, many datasources
The mechanism is a single application object and a single request context. You call gofr.New(), register routes on the returned app, and every handler receives a *gofr.Context. That context is the seam through which the framework reaches everything else: datasources, logging, tracing and metrics.
The dependency list in go.mod shows how wide that seam is. Postgres through github.com/lib/pq, MySQL through github.com/go-sql-driver/mysql, Redis through github.com/redis/go-redis/v9, Kafka through github.com/segmentio/kafka-go, MQTT through github.com/eclipse/paho.mqtt.golang, Google Pub/Sub through cloud.google.com/go/pubsub, and Dgraph through github.com/dgraph-io/dgo. Observability is OpenTelemetry at its base, with exporters for OTLP over gRPC and HTTP, Zipkin, and Prometheus (go.opentelemetry.io/otel plus the corresponding exporter modules). Routing sits on github.com/gorilla/mux, so the underlying router is a known quantity rather than a bespoke matcher.
That is the trade the framework makes. You get one context type with logging, tracing and datasource access already attached, and in exchange your handlers are written against GoFr's types. The repository layout reflects the same intent: pkg/ holds the framework, examples/ holds one runnable directory per concern (using-migrations, using-publisher, using-subscriber, using-cron-jobs, using-http-service, using-web-socket, using-s3-filestore, and others), and docs/ sits beside them. When you want to know how a feature is meant to be used, the example directory named after it is the most concrete source in the repository.
Installing GoFr and getting a first route answering
The README sets one prerequisite: Go version 1.26 or above. The module declares go 1.26.0 in go.mod, so the toolchain requirement is not advisory.
Installation is a normal module fetch. The README gives both the import path and the command form.
go get -u gofr.dev/pkg/gofrThe minimal program from the README registers one GET route and starts the server.
package main
import "gofr.dev/pkg/gofr"
func main() {
app := gofr.New()
app.GET("/greet", func(ctx *gofr.Context) (any, error) {
return "Hello World!", nil
})
app.Run() // listens and serves on localhost:8000
}Run it with go run main.go and open localhost:8000/greet. The handler signature is the part worth noticing: it returns (any, error) rather than writing to a response writer, so serialisation and error mapping are the framework's responsibility, not yours.
The repository also carries a Dockerfile that builds examples/http-server/main.go on golang:1.27, copies the binary onto alpine:3.24 with tzdata and ca-certificates, and exposes port 8000. If you want to see the framework running in a container before committing to it, that file is the shortest path, and it also documents the static-link build flags the project uses.
FROM golang:1.27
RUN mkdir -p /go/src/gofr.dev
WORKDIR /go/src/gofr.dev
COPY . .
RUN go build -ldflags "-linkmode external -extldflags -static" -a examples/http-server/main.go
FROM alpine:3.24
EXPOSE 8000Where the opinionated defaults become a constraint
The cost of a framework that owns your context is that it owns your context. Because handlers take *gofr.Context, your business logic sits behind a GoFr type. Moving that logic to net/http, to chi, or to a plain service layer means rewriting handler signatures and re-plumbing datasource access, even though the logic underneath is unchanged. This is the same bargain every full framework offers, and it is worth naming before you take it.
The second limitation is documentation depth. The README is a feature list with links; the behaviour of each feature lives in the docs site and in the examples directory. The README does not document rollback for migrations, and it does not state which datasources are covered by the health check feature beyond the phrase "for All Datasources". If you need a precise answer about migration rollback semantics or which backends the health endpoint probes, the README will not give it to you, and you should read the corresponding example and the package source before designing around it.
The third is scope. GoFr is aimed at microservices on Kubernetes. If your workload is a batch job, a CLI, or a single-process service with no datasource, the framework's defaults (a running server, datasource health checks, observability exporters) are weight you are carrying without using.
GoFr versus Gin, and versus a framework like Kratos
The comparison people reach for is Gin, and the difference is not speed, it is where the defaults live. Gin is a router with a middleware ecosystem: you choose a logger, choose an ORM, choose an OpenTelemetry integration, and assemble them. GoFr arrives with those choices already made and bound to the context. If your team already has a settled stack of logging and tracing libraries, Gin (or gorilla/mux, which GoFr itself uses underneath) lets you keep it. If your team keeps rebuilding that stack per service, GoFr's position is that the rebuild is the problem.
The other comparison in the same space is Kratos, which also targets Go microservices but approaches the problem from a generated-code and protobuf-first direction. GoFr's examples are hand-written handlers registered on an app object; there is no separate code-generation step described in the README. That makes the first hour with GoFr shorter, and it also means the API surface is the framework's own types rather than generated stubs you can regenerate from an interface definition.
Maintenance cadence, licence and upgrade cost
The repository is not archived, and the last push was on 2026-09-18. Releases are frequent: v1.61.0 on 2026-09-17, v1.60.1 on 2026-09-02, v1.60.0 on 2026-08-31. Frequent minor releases are a maintenance cost as well as a sign of movement, because a framework that owns your context can change that context. The upgrade path is a Go module version bump, and the framework's own go.mod pins a long list of dependencies, so a GoFr upgrade can move your OpenTelemetry, Redis, Kafka or gRPC middleware versions with it. Budget for reading the release notes at each bump rather than assuming a patch release is inert.
The licence is Apache-2.0, stated in the README badge and present as LICENSE at the repository root. Apache-2.0 is a permissive licence with an explicit patent grant, which is generally straightforward for commercial use, but the terms that apply to your organisation are a question for your own counsel, not something this review can settle. Note also that the module path is gofr.dev rather than a github.com path, so your import lines and any module proxy configuration should use gofr.dev as written in the README.
Editorial conclusion
Adopt GoFr if you are starting a Kubernetes-deployed Go service and want traces, metrics and datasource health without writing that plumbing yourself, and if the opinionated shape of gofr.Context suits your team. Do not adopt it if you want to keep gorilla/mux or chi routing at the centre of your design, or if you need a migration path off the framework later, because the datasource and context types are GoFr's own. Verify first that your Go toolchain is 1.26 or above, that the datasources you need appear under examples/, and that the observability exporter you intend to run is one of the OpenTelemetry exporters listed in go.mod.
Frequently asked questions
What Go version does GoFr require?
The README states that GoFr requires Go 1.26 or above, and go.mod declares go 1.26.0. The repository's own Dockerfile builds with golang:1.27.
What port does a GoFr application listen on by default?
The README's example calls app.Run() and notes in a comment that it listens and serves on localhost:8000. The repository Dockerfile also exposes port 8000.
Which databases and message brokers does GoFr support?
The dependency list in go.mod includes drivers for Postgres, MySQL, Redis, Kafka, MQTT, Google Pub/Sub and Dgraph. The examples directory has runnable directories for several of these, including using-publisher, using-subscriber and using-cloudsql.
How do I add GoFr to an existing Go project?
The README gives the import path gofr.dev/pkg/gofr and the command go get -u gofr.dev/pkg/gofr. Handlers are then registered on the app returned by gofr.New().
Official sources
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.
[](https://hysenlabs.com/projects/gofr-dev-gofr)