Stage 7 · Master
Workspace Layout, Design Principles, and the Platform Library
The go.work Workspace
Meridian is organized as five Go modules under a single go.work file from the outset — the reasoning for this boundary and how local replace directives wire libs/platform into every service.
Five Modules from the Outset
Meridian's repository root contains a go.work file listing five modules: apps/gateway, apps/identity-service, apps/community-service, apps/billing-service, and libs/platform. Unlike a project that starts as a single binary and introduces a workspace once a second module appears, Meridian's service boundaries are established at the repository's outset because the target architecture — four independently deployable services behind one gateway — is known in advance.
go 1.26
use (
./libs/platform
./apps/gateway
./apps/identity-service
./apps/community-service
./apps/billing-service
)Each use directive names a module directory. go build and go test commands run from the repository root resolve imports across these five modules without any module needing a published version of another.
The go.work File
A workspace file exists to let multiple Go modules be developed together, resolving imports against each module's local source rather than a tagged release. Meridian needs this immediately because every service module (apps/gateway, apps/identity-service, apps/community-service, apps/billing-service) depends on libs/platform, and that dependency changes frequently during scaffolding — a workspace avoids re-tagging libs/platform on every change.
Per-Service go.mod
Each service module declares its own go.mod with module path github.com/thesyscoder/meridian/apps/<service>, targets go 1.26, and includes a require plus a replace directive pointing at ../../libs/platform.
module github.com/thesyscoder/meridian/apps/identity-service
go 1.26
require github.com/thesyscoder/meridian/libs/platform v0.0.0
replace github.com/thesyscoder/meridian/libs/platform => ../../libs/platformThe replace directive is what makes libs/platform importable without a published module version. The go.work file makes this consistent across all four services without repeating the replace logic in a build script.
Why a Workspace Here, Not Later
| Signal | Present in Meridian from day one? | Justifies go.work |
|---|---|---|
| More than one binary that must build and run independently | Yes — four service binaries plus the shared library | Yes |
| Shared code imported by every service | Yes — libs/platform | Yes |
| A known target architecture, not a speculative one | Yes — documented in docs/architecture/services.md before code was written | Supports establishing the boundary early |
A project with one unknown-shaped destination benefits from starting as a single module and introducing a workspace only once a second module is justified by a concrete requirement. Meridian's destination — four independent services behind a gateway — was fixed before implementation began, so the workspace boundary is established immediately rather than earned incrementally. The distinction that still holds, and is covered in later chapters, is that business logic inside each service is not scaffolded ahead of the feature that requires it — only the workspace and module boundary are fixed up front.
The Decision
- go.work at the repository root lists five modules: libs/platform and four apps/<service> modules.
- Each service module has its own go.mod with a replace directive pointing at ../../libs/platform.
- Business logic within each service's internal/ packages is still added incrementally, only when a specific feature requires it — the workspace boundary is fixed, the implementation inside it is not.
- make tidy runs go work sync to keep all module go.sum files consistent after a libs/platform change.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.