Project Structure & Architecture
Sphere follows a pragmatic project structure that keeps code generation, server code, and business logic cleanly separated while staying fast to iterate on. The structure is based on the sphere-layout template and follows Go community best practices.
Architecture Philosophy
Sphere embraces a monolith-first approach with clean boundaries:
- Start with one binary using the standard project structure
- Share contracts via Protobuf and generated code across services
- Extract services only when scaling requires it
- Maintain clear boundaries via directories and interfaces
- Automate with Makefile targets to maintain repeatability
This approach allows you to begin with a modular monolith and easily scale to microservices without restructuring your codebase.
Overview
The project structure is designed to:
- Provide clear separation of concerns
- Support efficient code generation workflows
- Enable easy testing and development
- Scale from monolith to microservices
Directory Structure
├── api # Go files generated by Protobuf definitions
├── assets # Static files (e.g., UI assets, templates)
├── cmd # Application entry points
│ ├── app # Main application
│ └── tools # Developer tools
├── devops # DevOps and infrastructure files (e.g., Docker, CI/CD)
├── internal # Private application and library code
│ ├── biz # Business logic layer (use cases)
│ ├── config # Configuration loading and management
│ ├── pkg # Shared internal packages
│ │ ├── database # Database setup, including ent schemas and client
│ │ └── ... # Other shared utilities
│ ├── server # Server implementation (gRPC, HTTP)
│ └── service # Service layer implementing the API interfaces
├── proto # Protobuf source files (.proto)
├── scripts # Helper scripts for development
└── swagger # Generated Swagger/OpenAPI documentationKey Directories
At a glance, common top-level directories:
api/: Generated Go from.proto(do not edit)cmd/: Entrypoints and developer toolsinternal/: Private application code (service, biz, data, server)proto/: Protobuf contractsdevops/: CI/CD and infrastructurescripts/: Developer scripts and helpersswagger/: Generated OpenAPI assets
Layer Responsibilities
Transport Layer (internal/server/)
- HTTP request/response handling
- Protocol-specific concerns
- Middleware application
- Request routing
Service Layer (internal/service/)
- API contract implementation
- Request validation
- Response formatting
- Transport-agnostic logic
Business Layer (internal/biz/)
- Core business logic
- Use case orchestration
- Domain rules enforcement
- Transaction management
Data Layer (internal/pkg/database/)
- Data persistence
- Query optimization
- Schema management
- Database transactions
Notes
- Keep generated code under
api/separate and unedited - Group proto and services by domain + version (e.g.,
api.v1) - Add custom Make targets for project-specific tasks
- Modify the build process in the Makefile
However, maintain the core separation between generated code (api/), business logic (internal/biz/), and service implementations (internal/service/) to ensure code generation tools continue to work effectively.
Migration from Other Structures
If you’re migrating from other project layouts:
- From Standard Go Layout: Move business logic from
pkg/tointernal/biz/ - From DDD Layout: Align domain packages with proto package structure
- From Layered Architecture: Merge controller and service layers into
internal/service/ - From Hexagonal Architecture: Map ports/adapters to service/biz layers
The key is maintaining clear boundaries between transport, business logic, and data access while leveraging code generation for the transport layer.
Scaling Out
As your application grows, Sphere enables seamless scaling:
- Multiple binaries can reuse the same contracts and tooling
- Consistent errors, routing, and payloads via generators reduce drift between services
- Shared proto packages keep all services in sync
- Makefile targets ensure consistent build and generation processes across all services
Repository Strategy
Sphere recommends a pragmatic approach to repository organization:
Single Repository Approach (Recommended for Start)
- Keep everything in one repository initially
- Use Makefile-driven code generation for consistency
- Maintain clear module boundaries through interfaces
- Scale to multiple repositories only when necessary
Multi-Repository Strategy (When Scaling)
- Separate repositories for independent microservices
- Shared proto definitions in a dedicated repository
- Shared libraries in separate packages
- Consistent tooling across all repositories
The key is starting simple with a single monolithic structure and evolving to microservices only when business requirements demand it. The shared Protobuf contracts and generators ensure consistency across the entire system.