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

Golang Backend Real-World #1: Project Setup & Clean Folder Structure
Golang Backend Real-World #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.

About Leaf 47 Articles
"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."