# GoFr: an opinionated Go framework that ships observability and datasources with the service

> 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.

**gofr-dev/gofr** — An opinionated GoLang framework for accelerated microservice development. Built in support for databases and observability.

- Repository: https://github.com/gofr-dev/gofr
- Website: https://gofr.dev
- Stars: 20,878 · Forks: 1,769
- Language: Go
- License: Apache-2.0
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/gofr-dev-gofr

## 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.

```bash
go get -u gofr.dev/pkg/gofr
```

The minimal program from the README registers one GET route and starts the server.

```go
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.

```dockerfile
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 8000
```

## Where 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.

## 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.

## FAQ

### 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().

## Sources

- [gofr-dev/gofr on GitHub](https://github.com/gofr-dev/gofr)
- [License: Apache-2.0](https://github.com/gofr-dev/gofr/blob/development/LICENSE)
- [Project website](https://gofr.dev)
- [README](https://github.com/gofr-dev/gofr/blob/development/README.md)
- [Releases](https://github.com/gofr-dev/gofr/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/gofr-dev-gofr
