This is the first part of a blog series. I will create subsequent posts to improve the project step-by-step over time.
DISCLAIMER
This is a very opinionated approach to building a Golang app. The method explained here is based on my experience. You should review your workflow first to determine if this fits into your project. Alternatively, you can use this as a reference for building your own Golang backend project.
TL;DR
If you don't want to read the full explanation below, check out the GitHub repository to view the result:
https://github.com/hilmoo/go-backend-example/tree/blog/part-I
Overview
This is a backend written in Golang that features an HTTP API and an MCP server, allowing AI to interact with the backend. The HTTP API uses the Echo framework, and the MCP implementation uses the official SDK.
Project Structure
.
├── cmd → Backend entry point
├── internal
│ ├── app → Control plane responsible for wiring all components
│ ├── cmd → Command functions used by the entry point
│ ├── feature → Core business logic of the application
│ ├── model → Database models used across the application
│ ├── store → Data access layer for interacting with the database
│ └── transport → Transport layer handling user-facing interactions
└── migration → SQL migration filesI don't know the specific name for this structure, but it fits my workflow. I can focus on a single folder when creating a new feature, rather than jumping back and forth across different directories.
Logging
The logging implementation here is heavily inspired by this website. The method is called "wide events," where all information needed to diagnose an error is appended to a single log line rather than being scattered across multiple files. The implementation in Golang utilizes context since a single request uses a single context, the log data is populated within that context.
Database
In this project, I am using raw SQL to interact with the database. Why not use an ORM? It's simple: I don't like them. I know that when building simple queries, an ORM is very easy to use. However, an ORM adds another layer between my app and the database. I prefer working with something more raw rather than dealing with an abstraction layer.
Development
For development, this project uses Dev Containers. Read more about this here.
Deployment
Deployment relies on GoReleaser to build and generate binaries and Docker images. I love this tool, I can easily build for multiple targets and formats without writing numerous scripts solely for this purpose.