DEV Community

Aditya
Aditya

Posted on

2

Building Microservices with Go: A Step-by-Step Guide

Microservices have become the de facto standard for building scalable, maintainable, and robust backend systems. Go (Golang), with its simplicity, performance, and strong concurrency support, is an excellent choice for developing microservices. In this guide, we'll walk through building a microservice using a ready-to-use Go microservice template.

Why Go for Microservices?

  • Performance: Go compiles to native code and offers great runtime efficiency.
  • Simplicity: The language is easy to learn and encourages clean, readable code.
  • Concurrency: Goroutines and channels make concurrent programming straightforward.
  • Strong Standard Library: Go's standard library covers most needs for microservice development.

Project Structure Overview

A well-structured project is crucial for maintainability. Here’s a typical layout:

go-microservice-template/
├── cmd/
│   └── main.go                # Entry point
├── internal/
│   ├── api/
│   │   └── rest/
│   │       ├── rest.go        # REST server setup
│   │       ├── handler/
│   │       │   └── handler.go # HTTP handlers
│   │       └── router/
│   │           └── router.go  # Route definitions
│   ├── app/
│   │   └── app.go             # App lifecycle
│   ├── repository/
│   │   └── repository.go      # Data access
│   └── service/
│       └── service.go         # Business logic
├── pkg/
│   ├── models.go              # Shared models
│   └── response.go            # Response helpers
├── scripts/                   # Utility scripts
├── Makefile                   # Makefile for build automation
├── go.mod
├── go.sum
├── LICENSE
└── README.md
Enter fullscreen mode Exit fullscreen mode

Why This Structure Supports Scalable Microservices

A well-organized project structure is essential for building scalable and maintainable microservices. This template follows Go community best practices and separates concerns clearly, making it easy to extend, test, and manage as your service grows.

Folder-by-Folder Breakdown

  • cmd/: Contains the entry point(s) for your application. Each executable should have its own subfolder, making it easy to add CLI tools or multiple services in the future.
  • internal/: Holds all application-specific code. The internal directory restricts import access, ensuring that code here cannot be imported from outside the project, which enforces encapsulation and prevents accidental dependencies.
    • api/rest/: Contains REST server setup, handlers, and routers. This keeps your API layer modular and easy to update as endpoints grow.
    • app/: Manages application lifecycle and startup logic, centralizing configuration and initialization.
    • repository/: Handles data access, making it easy to swap databases or external services without affecting business logic.
    • service/: Contains business logic, keeping your core functionality decoupled from transport and storage layers.
  • pkg/: For code that can be shared across projects or is intended for public use. This is ideal for reusable models, helpers, and utilities.
  • scripts/: Stores automation and setup scripts, helping with DevOps, CI/CD, and local development tasks.

This separation of concerns allows teams to work independently on different parts of the service, supports testing and code reuse, and makes it straightforward to scale the codebase as requirements evolve. By following this structure, you ensure your microservice remains robust, modular, and ready for future growth.

Libraries Used

This template leverages several key Go libraries from the oss.nandlabs.io/golly suite to streamline development and testing:

  • oss.nandlabs.io/golly/rest: Provides REST server utilities and interfaces for building HTTP APIs.
  • oss.nandlabs.io/golly/lifecycle: Manages application lifecycle, including startup and graceful shutdown of components.
  • oss.nandlabs.io/golly/assertion: Used for expressive assertions in unit tests, making test code more readable and robust.

You can add more libraries as needed for your business logic, database access, or API integrations. All dependencies are managed via Go modules (go.mod).

Step 1: Clone the Template

Start by cloning the template repository:

git clone https://github.com/neo7337/go-microservice-template.git
cd go-microservice-template
Enter fullscreen mode Exit fullscreen mode

Step 2: Update the Module Name

Edit go.mod to use your own module path:

module github.com/yourusername/your-microservice
Enter fullscreen mode Exit fullscreen mode

Then tidy up dependencies:

go mod tidy
Enter fullscreen mode Exit fullscreen mode

Step 3: Define Your Data Models

Add or modify structs in pkg/models.go to represent your domain entities. For example:

type User struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Age   int    `json:"age"`
    Email string `json:"email"`
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Implement Business Logic

Write your core business logic in the internal/service/ package. This keeps your code modular and testable.

Step 5: Set Up Data Access

Implement repository functions in internal/repository/ to interact with databases or external APIs.

Step 6: Create API Handlers and Routes

  • Add handler functions in internal/api/rest/handler/ for each endpoint.
  • Register routes in internal/api/rest/router/router.go and link them to handlers.

Example: Adding a Concurrency Endpoint

To demonstrate Go's concurrency, the template includes a /api/concurrency-demo endpoint. This endpoint launches two goroutines in parallel—one fetching users, another simulating an external call—and aggregates their results:

func ConcurrencyDemoHandler(ctx rest.ServerContext) {
    type result struct {
        Source string      `json:"source"`
        Data   interface{} `json:"data"`
    }
    results := make(chan result, 2)

    go func() {
        users, _ := service.GetUsers()
        results <- result{Source: "users", Data: users}
    }()

    go func() {
        info := map[string]string{"message": "Hello from goroutine!"}
        results <- result{Source: "info", Data: info}
    }()

    resp := make(map[string]interface{})
    for i := 0; i < 2; i++ {
        r := <-results
        resp[r.Source] = r.Data
    }

    pkg.ResponseJSON(ctx, 200, resp)
}
Enter fullscreen mode Exit fullscreen mode

Sample response:

{
  "users": [
    {"id":1,"name":"John Doe","age":30,"email":"john.doe@mail.com"},
    {"id":2,"name":"Jane Smith","age":25,"email":"jane.smith@mail.com"}
  ],
  "info": {"message": "Hello from goroutine!"}
}
Enter fullscreen mode Exit fullscreen mode

Step 7: Customize Application Startup

Modify internal/app/app.go to register additional components or change startup behavior as needed.

Step 8: Run Your Microservice

Start your service locally:

go run cmd/main.go
Enter fullscreen mode Exit fullscreen mode

By default, your API will be available at http://localhost:8282/api.

Step 9: Extend and Organize

  • Add more packages under internal/ as your service grows.
  • Use the pkg/ directory for shared utilities and types.
  • Add scripts to the scripts/ directory for automation or setup tasks.

Step 10: Testing

The template includes example test cases for both the repository and response utility layers:

  • internal/repository/repository_test.go tests the GetUsers function, ensuring correct user data is returned.
  • pkg/response_test.go tests the ResponseJSON utility, verifying status code, headers, and JSON output.

Add your own tests alongside your code or in a dedicated test/ directory. To run all tests:

go test ./...
Enter fullscreen mode Exit fullscreen mode

Repository

You can find the template repository here: neo7337/go-microservice-template

Conclusion

With this template and step-by-step approach, you can quickly scaffold, develop, and scale robust Go microservices. The clear separation of concerns and modular structure make it easy to maintain and extend your services as your needs evolve.


Ready to build your next microservice? Fork the template and start coding!

Runner H image

Automate anything - Making research analysis effortless

Check out this winning submission to the Runner H "AI Agent Prompting" Challenge. 👀

Read more →

Top comments (0)

Feature flag article image

Create a feature flag in your IDE in 5 minutes with LaunchDarkly’s MCP server 🏁

How to create, evaluate, and modify flags from within your IDE or AI client using natural language with LaunchDarkly's new MCP server. Follow along with this tutorial for step by step instructions.

Read full post

👋 Kindness is contagious

Sign in to DEV to enjoy its full potential.

Unlock a customized interface with dark mode, personal reading preferences, and more.

Okay