Apr 30, 2025

Go doesn’t believe in frameworks, but teams still need them

Simplicity can be a burden sometimes

6 Min Read
Golang

Go is a powerful language known for its simplicity, speed, and concurrency model. But the Go community also traditionally takes a strong stance against frameworks and centralized conventions — and that’s where many teams, especially those coming from structured environments like Rails, Django, or FastAPI, hit a wall.

This post explores the structural gap in Go development, why it exists, and how Encore is helping fill that void with a convention-driven framework that brings clarity, consistency, and productivity back to backend development.

Go: Powerful, Minimal — and Unopinionated by Design

There is no explicit style guide, although there is certainly a recognizable “Go style”.

Official Go Website - FAQ

From its inception, Go has been designed to avoid the complexity that often comes with large frameworks. Its creators intentionally left many things out — project structures, routing, migrations, background processing — in favor of giving developers freedom and flexibility.

This philosophy has real benefits. Go’s simplicity makes it easy to learn. Its concurrency primitives (goroutines and channels) are elegant and performant. And its standard library is solid and efficient.

But as many teams have learned firsthand: minimalism at the language level doesn’t scale effortlessly to the team level.

Why Frameworks Exist

Frameworks like Ruby on Rails or Django exist for a reason: they encode best practices, reduce boilerplate, and help teams move faster by making thousands of decisions for you — decisions about naming, folder structure, routing, testing, and how to glue everything together.

They offer what Go intentionally avoids: opinions.

When you use Rails or Django, you get structure, defaults, and integrated tooling out of the box. When you use Go, you get a blank slate.

And that blank slate can be liberating — or paralyzing.

The Problem: Go Leaves Too Much Up to You

Decision paralysisCredit: cartoonresource / Adobe Stock

For individual developers or small projects, Go’s lack of structure may not seem like a problem. But for teams building serious systems, it introduces friction and inefficiency across the board.

Here’s what teams consistently run into:

1. No Shared Conventions

There’s no standard for project layout, file structure, service boundaries, or even how to write HTTP handlers. This leads to:

  • Internal debates over architecture
  • “Snowflake” services with custom layouts
  • Higher onboarding costs as each service is different

2. Too Many Decisions, Not Enough Guidance

In Go, many common tasks like background jobs, database migrations, and routing are handled through third-party libraries rather than built-in tooling. While the ecosystem offers high-quality options, there's no single "Go-endorsed" path or integrated framework, so teams often spend time researching libraries, wiring them together, and maintaining consistency across services.

3. Infrastructure is DIY

Since Go’s culture is intentionally anti-framework, most teams end up building everything themselves. That typically means spending precious development time on tasks not building any unique product value:

  • Writing boilerplate to connect services and handle cross-cutting concerns like tracing and auth
  • Managing secrets and configuration differently in each environment
  • Assembling infrastructure manually using tools like Terraform, Docker, and CI/CD scripts

4. Teams Drift Apart

Without enforced structure, codebases diverge. Teams working on different services develop their own conventions. As one engineer put it, "Every Go service felt like its own little world."

How Some Teams Solve This: Introducing Structure with Encore.go

Encore.go

Encore.go is one example of a framework that aims to help teams transition to Go more smoothly. Encore gives teams conventions, built-in tooling, and cloud-native defaults that eliminate boilerplate and reduce DevOps overhead — so developers can focus on building products, not plumbing.

“We would never have been able to build our ebooks product in the time we did without Encore. It provided exactly the clarity, tooling, and stability we needed.”

Mason Stewart, CTO at Bookshop.org

Encore includes:

  • Built-in functionality: Auth, routing, database migrations, service-to-service connection handling, etc.
  • Convention-driven development: Conventions for defining APIs, services, testing, integrating infrastructure, etc.
  • No configuration: One command to start the local environment, including all infrastructure.
  • Observability: Tracing, metrics, and structured logging are included by default and available in Encore's development dashboard.
  • Cloud-native design: Support for Docker or automatic deployment to AWS/GCP via Encore Cloud.

Rather than starting from scratch with raw Go, some teams use Encore as a way to adopt Go incrementally — without giving up the structure they’re used to.

Here’s what that can look like in practice:

Code Examples

Defining a service

Encore recognizes a Go package as a service. When running your app or deploying, it automatically provisions the required infrastructure and generates the connection boilerplate.

/my-app ├── encore.app // ... and other top-level project files │ ├── hello // hello service (a Go package) │   ├── hello.go // hello service code │   └── hello_test.go // tests for hello service │ └── world // world service (a Go package) └── world.go // world service code

See the app structure documentation for more details.

Defining APIs

Using the //encore:api annotation, you define an API endpoint in pure Go:

package hello // service name //encore:api public func Ping(ctx context.Context, params *PingParams) (*PingResponse, error) { msg := fmt.Sprintf("Hello, %s!", params.Name) return &PingResponse{Message: msg}, nil }

Encore then generates the required boilerplate and documentation automatically.

Learn more in the docs for defining APIs.

Running locally

Just run:

encore run

Encore will automatically set up the local infrastructure and a local development dashboard with API docs, architecture diagrams, tracing, and logs.

Cloud Deployment

Use Encore’s open-source tooling to build Docker images, or opt into Encore Cloud for automated infrastructure provisioning and deployment to your cloud on AWS or GCP.

Real Teams, Real Impact

Bookshop.org

Bookshop.org

Bookshop.org started moving from Rails to Go for better scalability. But the team quickly realized Go’s minimalism came at a cost.

“We didn’t have the conventions we were used to, and that created inconsistency in our applications. And while Go produces a single binary, there was still a lot of Terraform and bespoke deployment work.”

Mason Stewart, CTO at Bookshop.org

Adopting Encore brought back the structure and productivity they had with Rails — and the efficiency of Go and Google Cloud Run, automated through Encore Cloud, saved them serious money in the process.

“We’re on track to save over $60,000 per year compared to our legacy Rails application.”

Mason Stewart, CTO at Bookshop.org

Quiqup

Quiqup

Quiqup hit performance ceilings with Rails and wanted to move to Go — but without the microservices overhead. Encore’s modular monolith model struck the perfect balance.

"I loved the modular monolith concept of Encore. Microservices are too heavy to manage without a big team, and monoliths have their own issues. Encore was the perfect balance."

Danny Hawkins, CTO at Quiqup

Today, Quiqup runs over 30 services and 200+ API endpoints — with no dedicated DevOps engineers — thanks to Encore Cloud’s automatic infrastructure and observability.

“If we were onboarding people onto Go without Encore, it would have taken 2–3x longer to get productive.”

Danny Hawkins, CTO at Quiqup

The Bottom Line

Go’s minimalism is a mighty feature — but not when it slows teams down.

Encore.go brings the structure, defaults, and tooling that Go leaves out, helping teams ship faster with fewer DevOps headaches and less duplicated effort.

It’s not about replacing Go’s strengths, it's about not forcing every team to reinvent the same foundations every time.

Want more structure in your Go project?
We’re happy to chat and share what we’ve learned from helping other teams. Book a 1:1 intro — no pressure, just a conversation.

Encore

This blog is presented by Encore, the backend framework for building robust type-safe distributed systems with declarative infrastructure.

Like this article?
Get future ones straight to your mailbox.

You can unsubscribe at any time.