Go architectures · 3 MIN READ

Vertical slices: organize around a use case

Keep feature changes together without duplicating shared invariants.

Keep feature changes together without duplicating shared invariants. A vertical slice groups request parsing, application behavior and persistence for one capability, such as RenameProject. Trace the worked Go example, then compare the benefit with the cost before applying this design to your own project.

Architecture · A MAP OF THE IDEA

  1. Rename request
  2. RenameProject validation
  3. Persist the renamed project

Useful when

  • Most changes affect one feature
  • A team wants short paths from endpoint to behavior

Watch out

  • Cross-feature invariants need explicit ownership
  • Uncontrolled duplication can drift

Implementation & operation cost: Medium

Fit depends on the task

Small tool or CLI3/5
Domain-rich application5/5
Independent distributed services3/5

Editorial suitability, not benchmarks or a universal ranking. Styles describe different axes and can be combined.

01

The design decision

A vertical slice groups request parsing, application behavior and persistence for one capability, such as RenameProject. It can live inside a modular monolith and still call shared domain rules. It describes organization by change, not a new deployment topology.

02

A complete Go example

Read this program from the entry point and follow the calls shown in the diagram. The output is included at the end so you can check the behavior without a compiler.

go
package main

import (
	"errors"
	"fmt"
	"strings"
)

type Project struct{ Name string }

func RenameProject(p *Project, raw string) error {
	name := strings.TrimSpace(raw)
	if name == "" {
		return errors.New("name required")
	}
	p.Name = name
	return nil
}

func main() {
	p := Project{Name: "Draft"}
	fmt.Println(RenameProject(&p, "  Library  "))
	fmt.Println(p.Name)
}

// Output:
// <nil>
// Library
Read the code

RenameProject owns normalization and validation for one operation. The caller receives an error rather than modifying Name itself. A larger slice can include its HTTP DTO and SQL query without routing through layers that only forward arguments.

03

Tradeoffs and the simpler alternative

Extract a shared domain rule when several slices genuinely enforce the same invariant. Duplicated validation can drift, while an overgeneralized framework can make every change harder. Slices can share infrastructure without sharing their entire application model.

04

Organize by the change a user requests

Keep the command or query, validation, handler and response mapping for PlaceOrder close together. Share domain rules when they genuinely apply across use cases, not because two DTOs happen to have similar fields. A slice can use a concrete store for a simple query and a richer domain model for a complex command. Vertical slices describe the direction of code organization; they can run in one process and do not imply a service for each endpoint.

05

Make shared policy explicit

Authentication, authorization, observability and transaction management should have one understandable integration point. Keep endpoint-specific authorization near the use case when permission depends on loaded domain state. Avoid a global pipeline that catches and suppresses every error or makes transaction lifetime invisible. Two slices updating the same invariant need coordinated ownership, even if their files are in separate folders. Duplicating business rules across slices creates divergent behavior.

06

Test one slice end to end at its boundary

For a command, test invalid input, denied access, success and a failed durable write. For a query, test filtering and response shape without constructing unrelated domain workflows. Preserve the public route and event contracts while reorganizing packages. Extract shared code only after repeated changes reveal one stable responsibility. This approach makes feature changes local but needs conventions so each slice does not invent different error, logging and validation behavior.

TAKE THIS WITH YOU

Group code by use case and reason to change. Extract a shared domain rule when several slices genuinely enforce the same invariant. Duplicated validation can drift, while an overgeneralized framework can make every change harder. Slices can share infrastructure without sharing their entire application model.

Check your understanding

Which statement best describes Vertical slices: organize around a use case?

Go to the source

Progress stays in this browser. No account needed.