Golang Backend Real-World #1: Project Setup & Clean Folder Structure
  • Golang
  • Golang Real-World (Part 1): Project Setup & Clean Folder Structure

    Introduction

    Welcome to the first article of the Golang Backend Real-World Series.
    In this series, we will build backend applications using real-world engineering practices, including:

    • Clean folder structure
    • Modular design
    • Dependency injection
    • Config management
    • Logging & monitoring
    • REST API & middleware
    • Database, caching, background jobs
    • CI/CD, Docker, and production deployment

    This first part focuses on the foundation of every scalable backend project:
    👉 A clean, well-organized project structure.

    A messy folder structure will make your code hard to maintain, impossible to scale, and painful for future developers.
    A clean structure does the opposite — it boosts clarity, consistency, testability, and long-term growth.

    Why Folder Structure Matters

    When a project grows beyond a few files, bad structure causes:

    • Harder debugging
    • Tight coupling
    • Difficult onboarding for new developers
    • Code duplication
    • Complex refactoring

    A clean layout helps:

    • Organize source code by functionality
    • Make testing easier
    • Improve long-term maintainability
    • Follow industry conventions
    • Support microservices or modular expansion later

    Recommended Folder Structure

    Here is a widely used structure for production-ready Golang services:

    your-project/
    │
    ├── cmd/
    │   └── api/
    │       └── main.go
    │
    ├── internal/
    │   ├── config/
    │   ├── server/
    │   ├── user/
    │   │   ├── handler.go
    │   │   ├── service.go
    │   │   └── repository.go
    │   ├── auth/
    │   └── ...
    │
    ├── pkg/
    │   ├── logger/
    │   ├── response/
    │   └── middleware/
    │
    ├── configs/
    │   └── config.yaml
    │
    ├── scripts/
    │
    ├── test/
    │
    ├── go.mod
    └── go.sum
    

    Folder Breakdown

    1. /cmd

    Contains the entry point(s) of the application.

    Example:

    // cmd/api/main.go
    package main
    
    import (
        "your-project/internal/server"
    )
    
    func main() {
        server.Run()
    }
    

    2. /internal

    The most important folder.
    Contains application logic that should not be imported by other services.

    Structure suggestion:

    • config/ → load environment variables or YAML/JSON config
    • server/ → bootstrap Gin/Fiber/Echo server
    • user/, auth/, etc. → domain modules
    • Each module has:
      • handler.go (HTTP layer)
      • service.go (business logic)
      • repository.go (database)

    3. /pkg

    Reusable code that can be imported by other Go services.

    Examples:

    • Logging wrapper
    • Custom middleware
    • Standardized API response

    4. /configs

    Store external configs (YAML/JSON), ideal for multiple environments:

    configs/
    ├── config.dev.yaml
    ├── config.staging.yaml
    └── config.prod.yaml
    

    Install Required Dependencies

    For this series, we’ll use Gin for the HTTP framework.

    go get -u github.com/gin-gonic/gin
    

    Basic server:

    // internal/server/server.go
    package server
    
    import "github.com/gin-gonic/gin"
    
    func Run() {
        r := gin.Default()
    
        r.GET("/health", func(c *gin.Context) {
            c.JSON(200, gin.H{"status": "OK"})
        })
    
        r.Run(":8080")
    }
    

    Run your server:

    go run cmd/api/main.go
    

    API Response Standardization

    Create a small helper in /pkg/response.

    package response
    
    import "github.com/gin-gonic/gin"
    
    func Success(c *gin.Context, data interface{}) {
        c.JSON(200, gin.H{
            "success": true,
            "data":    data,
        })
    }
    
    func Error(c *gin.Context, message string) {
        c.JSON(400, gin.H{
            "success": false,
            "error":   message,
        })
    }
    

    This makes your API consistent and easy for frontend/mobile to consume.

    Best Practices You Should Follow Now

    ✔ Use internal/ for domain logic
    ✔ Group modules by feature, not by technical layer
    ✔ Create clear boundaries between handler → service → repository
    ✔ Keep reusable utilities inside pkg/
    ✔ Do not place random files in root directory
    ✔ Keep main.go small — only for startup, configs, DI

    Conclusion

    Your project is now ready with a clean, scalable, production-friendly structure.

    This foundation will make the next steps easy:

    • Building user modules
    • Connecting to MySQL/Postgres
    • Adding caching (Redis)
    • JWT authentication
    • Docker & deployment

    Coming Next (Part 2)

    👉 Implementing the User Module (handler, service, repository)
    With working APIs, schema, and DB migrations.

    Leaf

    "Thành công nuôi dưỡng sự hoàn hảo. Sự hoàn hảo lại nuôi lớn thất bại. Chỉ có trí tưởng tượng mới tồn tại."
    3 mins