ALERT: WIP
I wanted to create a ready-to-use, scalable Golang template for building web applications with HTMX and server-side rendering (SSR). While there are a few templates out there, I still feel there isn’t an ideal candidate that truly embraces SSR—especially when it comes to structuring HTML and static files using Go’s embed feature.
This template, GoSSR, is built from my personal experience developing several Golang projects. It implements Clean Architecture (modular approach) and Domain-Driven Design (DDD) Lite principles, with full support for server-side rendering.
Please check out the references and my notes on discussions and lessons learned while creating the GoSSR template. I’ve kept the Standard Go Project Layout in mind but also made some modifications where I found improvements necessary.
In GoSSR, you’ll notice I use a “consumer interface” approach (which you might find unconventional in other languages), along with SQLC for database interactions—which is one of my personal favorites and a core reason why the template is structured this way. It’s not perfect, but I think it works for me.
- Clean Architecture with Domain-Driven Design
- Server-side rendering
- PostgreSQL with SQLC for type-safe queries
- Modular design with independent business domains
- Chi router for HTTP routing
- Database migrations support
- Go 1.24+
- PostgreSQL
golang-migratesqlcgo-chi
Configuration is managed through config.go with environment variables. Please see .env_example for more details:
HTTP_ADDR: Server address (default::8080)DB_URL: PostgreSQL connection string
- Clone the repository
- Copy
.env_example→.envand configure - Initialize the database:
make up
- Start the development server:
make dev
Manage your database using the commands in the Makefile:
make up # Apply migrations
make down # Rollback migrationsThe root of the app is located at internal/app where everything is wired up. The module folder where you are spending most of your time is internal/module. Here are some examples:
- Located at
internal/module/articles domain/article.go: articles domain modelbusiness/service.go: Business logicstorage/postgres.go: Data persistence
- Located at
internal/module/categories domain/category.go: category domain modelbusiness/service.go: Business processingstorage/postgres.go: Data persistence
GET /article/{id}→ Get article by ID
GET /category/{id}→ Get category by ID
The application uses:
app.NewServer→ HTTP server setupapp.NewRouter→ Routing configuration- Chi middleware for logging and recovery
cmd→ Application entrypointsinternal→ Private application codeconfig→ Configuration managementpkg→ Shared utilitieshtml→ Template files for server-side rendering
The project follows Clean Architecture principles with clear separation of layers:
- Domain Layer → Domain models and interfaces
- Business Layer → Use cases and business rules
- Infrastructure Layer → External interfaces
- Transport Layer → HTTP handlers
Each module is self-contained with its own layers following DDD principles.
├── business/ (Service and Repository)
├── transport/ (Controller)
├── domain/ (entity and validation)
├── mapper/ (Mapping between model sqlc <-> domain)
├── queries/ (We write raw queries here which will be then used by sqlc to generate type safe code which is then put in /sqlc folder.)
├── storage/
└── sqlc/ (Generated by sqlc)
infras/ (shared infrastructure)
- domain -> entity (quite common option)
- transport -> controllers (simplier)
- business --> service (in which repository is simply a file given its succint content - mainly interface)
- https://go-proverbs.github.io/ (The interface should be slim. Well, basically the interface should be written where the consumers stand, not the producers (source of data)). So we might have multiple interfaces if we - the consumers - use multiple sources of data (such as using more than one tables). But we actually know exactly what we want to use. So interface only plays the role of a bridge. And we also know that in Golang, interface is IMPLICITLY implemented. I sometimes re-read this article https://www.alexedwards.net/blog/interfaces-explained to "entertain" about the concept of interface in Golang.
- https://github.com/golang-standards/project-layout (This is golden standard but surely still optional. I strictly follow this layout but also attempt to make some changes when needed. For example, I prefer Makefile at the root so that I dont have to jump between folders when configurating the app in productions. So just my opinionated way.)
- https://evrone.com/blog/go-clean-template (or https://archive.is/IjzTa) and their template: https://github.com/evrone/go-clean-template. The author uses controller rather than "transport", and they put all entities (and their respective services) in the same folder (controller, entity) except usecase (each case will have their own folder, for example: https://github.com/evrone/go-clean-template/tree/master/internal/usecase). I prefer to separate them into different folders/packages for better organization and scalability.
- https://github.com/bernardinorafael/go-boilerplate (This template also implements DDD but everthing in one domain is separeted by files, not by folders/packages. What if the service becomes larger? I find that creating separated packages/folders will help. I learn this from https://www.ardanlabs.com/blog/2017/02/package-oriented-design.html or https://archive.is/ECM0Z something called "Package Oriented Design"). Yet, I also find some usefuls (and common) packages in pkg such as sending email with html template or how to prepare the data with pagination or caching with Redis at https://github.com/bernardinorafael/go-boilerplate/blob/main/pkg/
- https://github.com/sklinkert/go-ddd (The idea of using migration.go at the root folder seems interesting.). I learn about validation of entity (domain) and using New pattern for initializing new entities. Take a look at https://github.com/sklinkert/go-ddd/blob/main/internal/domain/entities/seller.go. However, I don't get the idea of 4 folders in the internal: internal/application || domain || infrastructure || interface ||testhelpers.
- https://github.com/qiangxue/go-rest-api
- https://github.com/bxcodec/go-clean-arch
- https://github.com/Creatly/creatly-backend
- https://autostrada.dev. I honestly learned lots of things from Alex's book (Let's Go), that is the reason I mentioned his way of constructing Golang's based app here.
- https://philipptanlak.com/web-frontends-in-go/ or https://archive.is/ZiPT6 (I adopt a strategy to structe template layout in Laravel way from this blog. Kudo Philipp.)
- https://www.damianopetrungaro.com/posts/ddd-using-golang-tactical-design/ or https://archive.is/1xKhb (the snapshot created by myself) (I learn about domain and validation of the entity, how to initialize a new struct (domain/entity) via New pattern to trigger internal/"build-in" validation)
This project is licensed under the MIT License.