Go Architecture: Start With Boundaries, Not a Framework

Go does not give you one official application framework. Start with clear package boundaries, a simple layered design, and only add architecture when it improves delivery.

Aleksandr Perederei 2026-06-09 5 min

Go gives you a lot of freedom, perhaps too much when you are building your first service.

There is no official equivalent of Spring Boot or Django that decides where everything belongs. Search for the correct Go architecture and you will find many confident GitHub repositories, but no official answer from the Go team.

Which Go architecture should I choose?

I get this question often. My boring answer is: start with boundaries, not with an architecture diagram.

The first useful boundary

For a small API, three areas are often enough:

  1. transport, such as HTTP handlers
  2. business logic
  3. data access

Call them API, service, and repository if you like. Call it layered architecture or onion architecture. I do not care much about the label. I care whether a new engineer can answer: where does this change belong, and what is it allowed to call?

In a typical executable Go project, I also expect to see:

  • cmd/ for executable entry points
  • internal/ for application code that should not become a public dependency
  • small packages with clear responsibilities

I like internal/ because it is not architecture theatre. The compiler enforces it. A slide cannot stop another package from importing something it should not.

Reuse must be genuinely reusable

A common mistake is moving application-specific behavior into a shared package because it looks reusable today.

A shared logger, tracer, or organization-wide monitoring setup can belong in a reusable package. A business API usually should not.

One real example from my work involved monetary rounding. Different countries had different rules. Hungary, in particular, had enough rounding conditions to make the supposedly simple helper surprisingly unpleasant. Several teams processing money needed exactly those rules, so sharing the implementation made sense.

The test is not “can two callers import this?” The test is “does this represent a stable capability that several applications genuinely share?”

Sophisticated architecture can make delivery worse

I once worked on a new Go service designed around a sophisticated domain-driven architecture. The team was not junior. We had senior and Staff engineers, managers, and plenty of discussion about doing architecture properly.

After six months, we still could not ship anything useful.

The older monolith could deliver a comparable feature in roughly three months.

We replaced much of that design with a more direct controller-and-service style. Time to market fell from roughly six months to around two weeks. Later, we launched one country in a day.

That was a useful correction for me. Experienced engineers can overbuild a service just as effectively as beginners can.

A practical decision rule

Start simple. Add another layer, abstraction, or pattern when you can point to the pain it removes:

  • duplicated business rules
  • unstable external dependencies
  • difficult testing
  • unclear ownership
  • changes leaking across boundaries

If the explanation is mostly architectural vocabulary, wait. You can always add complexity later. Removing it after six months is much more expensive.

For a broader review process, see architecture review mentoring and system design coaching.

Aleksandr Perederei

About the author

Aleksandr Perederei is a Principal Engineer, former Staff Software Engineer, Engineering Manager, and CTO. He has mentored 120+ engineers on system design, technical leadership, promotion evidence, career direction, and stronger engineering judgment.

Get engineering articles in your inbox

Practical advice on system design, technical leadership, and career growth. No spam.

Book Your Growth Session

Let's identify your #1 skill gap and create a 90-day learning plan to level up your engineering abilities.

Powered by Cal.com - No account required