Scaffold a new Go backend project with Clean Architecture, Dig DI, and testify. Use when the user asks to create, scaffold, or bootstrap a new Go project.
Scanned 9/3/2026
Install to Claude Code
npx -y skills add rios0rios0/guide --skill scaffold-go-project --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Scaffold Go Project?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/rios0rios0-scaffold-go-project)More formats (shields.io, HTML) on the badges page.
---
name: scaffold-go-project
description: Scaffold a new Go backend project with Clean Architecture, Dig DI, and testify. Use when the user asks to create, scaffold, or bootstrap a new Go project.
---
Scaffold a new Go backend project following Clean Architecture with domain/infrastructure separation, Dig DI, testify testing, and standard naming conventions.
For detailed Go conventions, refer to the Go rule. For architecture patterns, refer to the Architecture rule. For testing standards, refer to the Testing rule. For Makefile setup, refer to the CI/CD rule.
## Directory Structure
Create the following layout:
```
<project>/
├── cmd/
│ └── <app>/
│ ├── main.go
│ └── dig.go
├── internal/
│ ├── container.go
│ ├── domain/
│ │ ├── commands/
│ │ │ └── container.go
│ │ ├── entities/
│ │ │ └── container.go
│ │ └── repositories/
│ └── infrastructure/
│ ├── controllers/
│ │ ├── container.go
│ │ ├── mappers/
│ │ ├── requests/
│ │ └── responses/
│ └── repositories/
│ ├── container.go
│ ├── mappers/
│ └── models/
├── test/
│ ├── domain/
│ │ ├── builders/
│ │ ├── doubles/
│ │ │ └── repositories/
│ │ └── helpers/
│ └── infrastructure/
│ └── doubles/
│ └── repositories/
├── go.mod
├── go.sum
├── Makefile
└── README.md
```
## Step-by-Step
### 1. Initialize the module
```bash
mkdir <project> && cd <project>
go mod init <module-path>
```
### 2. Create the domain layer -- entities (pure, no framework tags)
```go
// internal/domain/entities/user.go
package entities
type User struct {
ID string
Name string
Email string
}
```
### 3. Create repository contracts
```go
// internal/domain/repositories/users_repository.go
package repositories
import "module/internal/domain/entities"
type UsersRepository interface {
FindAll() ([]entities.User, error)
FindByID(id string) (*entities.User, error)
Insert(entity *entities.User) error
}
```
### 4. Create commands (business logic)
```go
// internal/domain/commands/list_users_command.go
package commands
import (
"module/internal/domain/entities"
"module/internal/domain/repositories"
)
type ListUsersCommand struct {
repo repositories.UsersRepository
}
func NewListUsersCommand(repo repositories.UsersRepository) *ListUsersCommand {
return &ListUsersCommand{repo: repo}
}
func (c *ListUsersCommand) Execute() ([]entities.User, error) {
return c.repo.FindAll()
}
```
### 5. Create infrastructure implementations (prefixed with library name)
```go
// internal/infrastructure/repositories/pgx_users_repository.go
package repositories
import "module/internal/domain/entities"
type PgxUsersRepository struct {
// db connection
}
func NewPgxUsersRepository() *PgxUsersRepository {
return &PgxUsersRepository{}
}
func (r *PgxUsersRepository) FindAll() ([]entities.User, error) {
// implementation
}
```
### 6. Create controllers
```go
// internal/infrastructure/controllers/list_users_controller.go
package controllers
import (
"net/http"
"module/internal/domain/commands"
)
type ListUsersController struct {
command *commands.ListUsersCommand
}
func NewListUsersController(command *commands.ListUsersCommand) *ListUsersController {
return &ListUsersController{command: command}
}
func (c *ListUsersController) Execute(w http.ResponseWriter, r *http.Request) {
// call command, map response, write HTTP response
}
```
### 7. Set up Dig for dependency injection
Create `container.go` files per layer. Each layer registers its own providers:
```go
// internal/infrastructure/repositories/container.go
package repositories
import "go.uber.org/dig"
func RegisterProviders(container *dig.Container) error {
if err := container.Provide(NewPgxUsersRepository); err != nil {
return err
}
return nil
}
```
```go
// internal/domain/commands/container.go
package commands
import "go.uber.org/dig"
func RegisterProviders(container *dig.Container) error {
if err := container.Provide(NewListUsersCommand); err != nil {
return err
}
return nil
}
```
```go
// internal/container.go
package internal
import (
"go.uber.org/dig"
"module/internal/domain/commands"
"module/internal/infrastructure/controllers"
"module/internal/infrastructure/repositories"
)
func RegisterProviders(container *dig.Container) error {
if err := repositories.RegisterProviders(container); err != nil {
return err
}
if err := commands.RegisterProviders(container); err != nil {
return err
}
if err := controllers.RegisterProviders(container); err != nil {
return err
}
return nil
}
```
```go
// cmd/<app>/dig.go
package main
import (
"go.uber.org/dig"
"module/internal"
"module/internal/infrastructure/controllers"
)
func injectController() *controllers.ListUsersController {
container := dig.New()
if err := internal.RegisterProviders(container); err != nil {
panic(err)
}
var ctrl *controllers.ListUsersController
if err := container.Invoke(func(c *controllers.ListUsersController) {
ctrl = c
}); err != nil {
panic(err)
}
return ctrl
}
```
### 8. Create test structure
- Place test files next to production files with `_test.go` suffix
- Unit tests do not need build tags — Go runs `_test.go` files by default. Add build flags (`//go:build integration`, `//go:build e2e`, etc.) only for tests that require external infrastructure
- Use `stretchr/testify` suites and `assert`/`require` for assertions
- Create builders in `test/domain/builders/` for test data
- Create doubles (stubs/dummies) in `test/domain/doubles/repositories/`
- Every test must use `// given`, `// when`, `// then` comment blocks
- Unit tests must call `t.Parallel()` at the top
Refer to the Go rule (Testing section) and the Testing rule for full conventions.
### 9. Create Makefile
The project Makefile must import from the shared [pipelines repository](https://github.com/rios0rios0/pipelines) and expose `lint`, `test`, and `sast` targets. Refer to the CI/CD rule for details.
## Naming Quick Reference
| Component | File | Struct | Method |
|-----------------------|--------------------------------|---------------------------|-----------------------------------|
| Command | `<op>_<entity>_command.go` | `<Op><Entity>Command` | `Execute` |
| Controller | `<op>_<entity>_controller.go` | `<Op><Entity>Controller` | `Execute` |
| Repository (contract) | `<entity>_repository.go` | `<Entity>Repository` | varies |
| Repository (impl) | `<lib>_<entity>_repository.go` | `<Lib><Entity>Repository` | varies |
| Mapper | `<entity>_mapper.go` | `<Entity>Mapper` | `ToEntity`/`ToModel`/`ToResponse` |
| Container | `container.go` | -- | `RegisterProviders` |
## Key Rules
- Use a **short abbreviation** of the type as the method receiver (e.g., `c` for Command, `r` for Repository)
- Only attach methods to a struct when the method mutates state
- Entities MUST be free of framework tags -- pure business logic only
- No Services layer in Go projects
- Use **Logrus** (`github.com/sirupsen/logrus`) for ALL logging with alias `logger`
- All file names use **snake_case**
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!