Organize Like a Pro: A Simple Guide to Go Project Folder Structures

Bartu Kocakara
15 min readNov 29, 2024

When we talk about folder structure in Golang (or really any programming language), we’re referring to how we organize our files and directories within a project. This organization acts like a roadmap, helping developers maintain, navigate, and scale their projects by clearly separating different parts, like concerns, modules, and functionalities. Following some common conventions in Go not only makes reading and collaborating easier but also sets the stage for maintaining the project in the long run.

Why is Folder Structure Important?

Having a well-organized folder structure is really important for a few key reasons:

  • Separation of Layers: It keeps different parts of your project — like business logic, data access, and API handling — in their own folders. This way, developers can focus on specific areas without feeling overwhelmed or confused.
  • Better Organization: By neatly sorting your code and its dependencies, larger projects become a lot easier to navigate. You’ll always know where to find what you need!
  • Reusability: A good structure lets you create components or packages that you can use in different parts of the project, saving you time and effort.
  • Easier Maintenance: When everyone follows a consistent folder setup, it’s much simpler to find and update code. This leads to better long-term management of the project.
  • Modularity: An effective folder structure encourages modular design, making it easier to add new features as your project grows.

In short, a smart folder structure makes your development process smoother and helps your project thrive!

Common Folder Structures in Golang

Here are some popular folder structures used in Golang projects:

1. Flat Folder Structure:

A flat folder structure is an organizational approach where all files are stored directly in the root directory, without any deep nesting or multiple subdirectories. This simplicity makes it easy to navigate and manage, particularly for small or straightforward projects.

project/
├── main.go # Application entry point
├── handler.go # HTTP handlers
├── service.go # Business logic
├── repository.go # Database repository
├── config.go # Configuration settings
├── utils.go # Utility functions
├── go.mod # Go module file
└── go.sum # Go module dependency file

Use Cases:

  • Small Projects: Ideal for projects with low complexity, allowing developers to manage all functionalities within a few files.
  • Prototypes and MVPs: Perfect for rapidly building prototypes or minimum viable products (MVPs), facilitating quick iterations without the need for organized folders.
  • Command-Line Tools: Well-suited for small command-line applications that only require a few support files, making execution and testing straightforward.
  • Learning and Experimentation: Beneficial for beginners who are learning a new programming language or framework, as it minimizes the complexity of file organization.

2. Layered Structure:

In a layered structure, the application is organized into different layers, such as controllers (or handlers), services, repositories, and models. Each layer has its specific role, making the code easier to manage.

project
├── cmd # Command-related files
│ └── app # Application entry point
│ └── main.go # Main application logic
├── internal # Internal codebase
│ ├── handlers # HTTP request handlers (controllers)
│ │ └── user_handler.go # User-specific handler
│ ├── services # Business logic (service layer)
│ │ └── user_service.go # User-specific service
│ ├── repositories # Data access (repository layer)
│ │ └── user_repo.go # User-specific repository
│ └── models # Data models (entities)
│ └── user.go # User model
├── pkg # Shared utilities or helpers
├── configs # Configuration files
├── go.mod # Go module definition
└── go.sum # Go module checksum file

Use Cases:

  • Medium-Sized Projects: Ideal for applications where there’s a need for clear separation between different functionalities and layers.
  • Separation of Concerns: Promotes a clean architecture where handlers are solely responsible for managing requests, delegating business logic to services, and data access to repositories.
  • Unit Testing: Each layer can be independently unit-tested, ensuring that changes in one layer do not affect the others, thus enhancing maintainability.

3. Domain-Driven Design:

In Domain-Driven Design (DDD), the application is divided into domains or bounded contexts, where each domain owns its own layers, including models, repositories, and services. This approach helps to isolate logic and keep the code domain-specific, promoting better organization and clarity.

project
├── cmd # Command-related files
│ └── app # Application entry point
│ └── main.go # Main application logic
├── internal # Internal codebase
│ ├── user # Domain 'user'
│ │ ├── handler.go # User-specific handler
│ │ ├── service.go # User-specific service
│ │ ├── repository.go # User-specific repository
│ │ └── user.go # User model
│ └── product # Domain 'product'
│ ├── handler.go # Product-specific handler
│ ├── service.go # Product-specific service
│ └── repository.go # Product-specific repository
├── pkg # Shared utilities
├── configs # Configuration files
├── go.mod # Go module definition
└── go.sum # Go module checksum file

Use Cases:

  • Complex Projects: Best for applications with multiple business domains, ensuring that each domain can evolve independently without affecting others.
  • Decoupling and Scalability: Useful when different parts of the application require isolation for scalability and maintainability.
  • Modularity: Promotes modularity, as each domain can be managed and developed separately, allowing teams to work on specific domains without conflicts.

4. Clean Architecture:

Clean Architecture organizes the application into distinct layers, each with explicit dependencies pointing inwards. This structure ensures that the core business logic remains independent of external systems, such as databases, frameworks, or user interfaces.

project
├── cmd/ # Command-related files
│ └── app/ # Application entry point
│ └── main.go # Main application logic
├── internal # Internal codebase
│ ├── delivery/ # External layer (HTTP Handlers, gRPC, etc.)
│ │ └── http/ # HTTP delivery
│ │ └── user_handler.go # User-specific HTTP handler
│ ├── usecases/ # Use Cases (business logic layer)
│ │ └── user_service.go # User-specific service logic
│ ├── repository/ # Repository (data access, external services)
│ │ └── user_repo.go # User-specific data access
│ └── entities/ # Entities (core models, domain objects)
│ └── user.go # User model
├── pkg/ # Shared utilities or helpers
├── configs/ # Configuration files
├── go.mod # Go module definition
└── go.sum # Go module checksum file

Key Principles:

  • Core Entities: Domain models are at the center of the architecture, ensuring business logic is the primary focus.
  • Use Cases: Encapsulate application-specific business rules, defining how the entities interact.
  • Delivery Layer: Manages external interactions through various interfaces (APIs, CLI, gRPC).
  • Repositories: Handle data access, allowing interaction with databases and third-party services without coupling to the business logic.

Use Cases:

  • Large, Scalable Projects: Ideal for applications that need to adapt and scale over time without compromising core functionality.
  • Independent Testing: Facilitates easy testing of the core logic without dependencies on frameworks, databases, or other external services, enhancing maintainability and flexibility.

5. Modular Structure:

A modular structure organizes the application into loosely coupled, self-contained modules, each with its own codebase. This approach allows each module to focus on specific functionalities or business units, improving reusability and scalability.

project/
├── user_module/ # User module
│ ├── handler/ # Handlers for user-related requests
│ ├── service/ # Business logic for user operations
│ ├── repository/ # Data access layer for user data
│ ├── user.go # User model definition
│ ├── go.mod # User module Go module definition
│ └── go.sum # User module Go module checksum file
├── product_module/ # Product module
│ ├── handler/ # Handlers for product-related requests
│ ├── service/ # Business logic for product operations
│ ├── repository/ # Data access layer for product data
│ ├── product.go # Product model definition
│ ├── go.mod # Product module Go module definition
│ └── go.sum # Product module Go module checksum file
├── api_gateway/ # API gateway to manage different services
│ ├── main.go # Main entry point for API gateway
│ ├── go.mod # API gateway Go module definition
│ └── go.sum # API gateway Go module checksum file
└── configs/ # Shared configuration files

Use Cases:

  • Microservices: Ideal for applications built on microservices architecture, where different teams can work independently on separate modules.
  • Decoupling and Scalability: Encourages a clear separation of concerns, allowing each module to be developed, tested, and deployed independently.
  • Independent Dependency Management: Each module can have its own go.mod file, facilitating separate management of dependencies and reducing conflicts between modules.

6. Feature-Based Folder Structure:

In a feature-based folder structure, each feature or functionality of the application is treated as a separate unit. All code related to that feature, including handlers, services, repositories, and more, resides within that feature’s directory. This approach enhances cohesion within features and promotes the encapsulation of feature-specific logic.

project/
├── cmd/
│ └── app/
│ └── main.go # Main application logic
├── internal/
│ ├── user/ # Feature: User
│ │ ├── handler/ # User-specific HTTP Handlers
│ │ ├── service/ # User-specific Business Logic
│ │ ├── repository/ # User-specific Data Access
│ │ └── user.go # User Model
│ ├── product/ # Feature: Product
│ │ ├── handler/ # Product-specific HTTP Handlers
│ │ ├── service/ # Product-specific Business Logic
│ │ ├── repository/ # Product-specific Data Access
│ │ └── product.go # Product Model
│ ├── order/ # Feature: Order
│ │ ├── handler/ # Order-specific HTTP Handlers
│ │ ├── service/ # Order-specific Business Logic
│ │ ├── repository/ # Order-specific Data Access
│ │ └── order.go # Order Model
├── pkg/ # Shared utilities or helpers
│ └── logger.go # Logging utilities
├── configs/ # Configuration files
├── go.mod # Go module definition
└── go.sum # Go module checksum file

Characteristics:

  • Encapsulation: Each feature encapsulates its own logic, models, and layers, minimizing unwanted dependencies.
  • Scalability: The structure can easily grow as new features are added, simply by creating new feature directories.
  • Focus on Business Needs: Since the organization revolves around features, it aligns closely with business requirements, making it intuitive for development teams.
  • High Cohesion: Related code for each feature is grouped together, making it easier to maintain and enhance the codebase for specific functionalities.

Use Cases:

  • Large Applications: Best suited for large applications that consist of multiple distinct features, such as user management, product catalogs, or order processing, which can be logically separated.
  • Feature Teams: Particularly useful for teams organized around feature ownership, where each team manages a feature end-to-end, enhancing collaboration and accountability.

7. Hexagonal Architecture:

Hexagonal Architecture, commonly referred to as Ports and Adapters, is an architectural pattern that emphasizes the separation of the core business logic from external dependencies. In this structure, the core interacts with the outside world through ports (which are interfaces), while external systems such as databases and web frameworks act as adapters that implement these interfaces.

project/
├── cmd/
│ └── app/
│ └── main.go # Main application logic
├── internal/
│ ├── core/ # Core business logic (Entities and Use Cases)
│ │ ├── user/ # User feature
│ │ │ ├── entity.go # User Entity (Domain Object)
│ │ │ └── usecase.go # Business Logic (Use Case)
│ │ └── product/ # Product feature, similarly structured
│ │ └── ... # Product-related files
│ ├── adapters/ # Adapters implementing interfaces for external systems
│ │ ├── database/ # Database adapters (repositories)
│ │ │ └── user_repo.go # User repository implementation
│ │ ├── api/ # API adapters (HTTP Handlers)
│ │ │ └── user_handler.go # User-specific HTTP Handler
│ │ └── messaging/ # Messaging systems (e.g., Kafka)
│ │ └── user_event.go # User event messaging
│ └── ports/ # Ports (Interfaces)
│ ├── user_repository.go # User repository interface
│ ├── user_service.go # User service interface
│ └── ... # Other port interfaces
├── pkg/ # Shared utilities
├── configs/ # Configuration files
├── go.mod # Go module definition
└── go.sum # Go module checksum file

Characteristics:

  • Core Independence: The core business logic operates independently from external layers such as frameworks, databases, and APIs. This independence enhances maintainability and flexibility.
  • Ports (Interfaces): Ports define how the core business logic interacts with external systems, allowing for clear contracts between the core and its adapters.
  • Adapters: Adapters (e.g., for databases, APIs, and messaging) can be easily swapped out without impacting the core logic. This facilitates testing and refactoring, as the core can be tested in isolation from external dependencies.

Use Cases:

  • Decoupled Business Logic: Ideal for applications where the business logic must remain decoupled from external systems like databases, APIs, or UI frameworks, ensuring flexibility and adaptability.
  • Projects with Changing External Systems: Particularly useful for projects requiring flexibility, where external systems may change over time, allowing the application to adapt without major rewrites to the core logic.

8. Monorepo Structure:

A monorepo is a single repository that houses multiple services or libraries. This structure is commonly used in large organizations, allowing different projects to be developed and deployed independently while still living within a unified codebase.

project/
├── services/
│ ├── user-service/
│ │ ├── cmd/
│ │ │ └── main.go # User service main application logic
│ │ ├── internal/ # Internal codebase for user service
│ │ │ ├── handler/ # User-specific HTTP handlers
│ │ │ ├── service/ # User-specific business logic
│ │ │ ├── repository/ # User-specific data access
│ │ │ └── models/ # User models
│ │ ├── go.mod # User service Go module definition
│ │ └── go.sum # User service Go module checksum file
│ └── product-service/ # Product service
│ ├── cmd/ # Command-related files for product service
│ ├── internal/ # Internal codebase for product service
│ └── go.mod # Product service Go module definition
├── libs/ # Shared libraries across multiple services
│ ├── logging/ # Logging library
│ ├── authentication/ # Authentication library
│ └── utils/ # Utility functions
├── go.mod # Top-level Go module definition
└── go.sum # Top-level Go module checksum file

Characteristics:

  • Multiple Services: Each service (e.g., user-service, product-service) is self-contained and operates independently, but they all reside within the same repository.
  • Shared Libraries: Common utilities and libraries (like logging and authentication) can be organized in a libs/ directory, allowing for reuse across different services.
  • Shared Modules: The project can have a single top-level go.mod file for the monorepo, or each service can have its own go.mod file, depending on the desired modularity.
  • Code Sharing and Consistency: Encourages sharing code and maintaining consistency across multiple services, reducing duplication and ensuring standardization.

Use Cases:

  • Large Organizations: Ideal for large organizations with multiple teams that work on independent services while requiring shared libraries and consistent practices.
  • Microservices Architecture: Particularly effective for microservice architectures or multi-service systems, as it simplifies collaboration and coordination within a single repository.

9. CQRS (Command Query Responsibility Segregation):

In CQRS (Command Query Responsibility Segregation), the command and query operations are organized into separate models. Commands are responsible for mutating the state (e.g., creating or updating data), while queries focus solely on reading data. This structure enhances the separation of concerns in handling requests.

project/
├── cmd/
│ └── app/
│ └── main.go # Main application logic
├── internal/ # Internal codebase
│ ├── commands/ # Commands (mutate state)
│ │ ├── create_user.go # Command to create a user
│ │ ├── update_user.go # Command to update a user
│ │ └── delete_user.go # Command to delete a user
│ ├── queries/ # Queries (read data)
│ │ └── get_user.go # Query to get user data
│ ├── repositories/ # Repositories for data access
│ │ └── user_repo.go # User repository
│ ├── models/ # Domain models
│ │ └── user.go # User domain model
│ └── services/ # Business logic
│ └── user_service.go # User service logic
├── configs/ # Configuration files
├── go.mod # Go module definition
└── go.sum # Go module checksum file

Characteristics:

  • Separation of Responsibilities: Commands and queries are divided into distinct models, simplifying scaling and maintenance of the codebase.
  • Scalable Architecture: This structure is particularly suited for applications where read and write operations need to be optimized separately, making it ideal for large-scale systems.
  • Decoupling: Promotes a clear separation between command and query handling logic, allowing for easier management of both operations.

Use Cases:

  • Distinct Read and Write Needs: Best for applications where read and write operations must be managed differently, especially in event-driven architectures or high-performance applications.
  • Event Sourcing and Consistency: Useful for systems that require event sourcing or have complex data consistency requirements, enabling clearer handling of changes in state.

10. Onion Architecture:

Onion Architecture emphasizes the separation of concerns by organizing code into concentric circles (or layers) around a central core. The innermost layer represents the business logic and domain model, while the outer layers contain external dependencies, such as frameworks, UI, and databases.

project/
├── cmd/
│ └── your-app/
│ └── main.go # Application entry point
├── internal/
│ ├── domain/ # Core business logic and entities
│ │ ├── entity.go # Domain entities
│ │ └── service.go # Domain services
│ ├── application/ # Application services
│ │ ├── usecase.go # Use cases interacting with domain
│ └── infrastructure/ # External infrastructure
│ ├── persistence/ # Database implementations
│ │ ├── repository.go # Repository for database interaction
│ ├── api/ # Web API layer
│ │ └── handler.go # HTTP handlers
│ └── ... # Other external services (message brokers, etc.)
├── pkg/
│ └── shared/ # Shared code across the project (helpers, utils)
├── configs/ # Configuration files (YAML, JSON, etc.)
│ └── config.yaml
└── go.mod # Go module file

Characteristics:

  • Layered Approach: The architecture is structured in concentric circles, with the innermost layer representing the core domain and the outer layers representing the application’s interfaces and infrastructure.
  • Dependency Inversion: The core domain logic remains independent of external frameworks and technologies, promoting maintainability and testability.
  • Separation of Concerns: Each layer has distinct responsibilities, helping to isolate changes and minimize side effects.
  • Focus on Business Logic: The core business logic stays at the center, allowing the application to evolve without impacting external dependencies.
  • Testability: Since the core logic is decoupled from the infrastructure, it is easier to write unit tests for the domain and application layers.

Use Cases:

  • Complex Business Domains: Suitable for applications with intricate business rules that require a clear separation of concerns.
  • Long-Term Projects: Ideal for projects expected to evolve over time, enabling developers to adapt to changes in business requirements without significant rewrites.
  • Teams with Clear Roles: Works well when different teams are responsible for various layers of the application (e.g., business logic vs. infrastructure).

11. Common Architecture:

Common Structure is suited for simpler projects or scenarios where speed of development and ease of understanding are prioritized over strict architectural guidelines. It allows for flexibility but may lead to less maintainable code in the long run.

project/
├── cmd/ # Main applications for this project
│ └── myapp/ # Directory for the myapp executable
│ └── main.go # Application entry point
├── internal/ # Private application and library code
│ ├── app/ # Application-specific code
│ │ └── myapp/ # Application code for myapp
│ │ ├── handler.go # HTTP handlers
│ │ └── service.go # Business logic
│ ├── pkg/ # Shared internal code (private libraries)
│ │ └── myprivlib/ # Shared library for internal use
│ ├── domain/ # Domain models and services
│ │ ├── entity.go # Domain entities
│ │ └── service.go # Domain services
│ └── infrastructure/ # External infrastructure code
│ ├── persistence/ # Database implementations
│ │ └── repository.go # Repository for database interaction
│ ├── api/ # Web API layer
│ │ └── handler.go # API handlers
│ └── messaging/ # Messaging systems (e.g., Kafka)
│ └── producer.go # Messaging producer
├── pkg/ # Library code for external use
│ └── mypubliclib/ # Public library for external use
├── vendor/ # Application dependencies
├── api/ # OpenAPI/Swagger specs, JSON schema files
│ └── api_spec.yaml # API specification file
├── web/ # Web application components
│ ├── static/ # Static assets (CSS, JS)
│ └── templates/ # Server-side templates
├── configs/ # Configuration files
│ └── config.yaml # Default configuration
├── init/ # System init configurations
│ └── myapp.service # Systemd service file
├── scripts/ # Build, install, analysis scripts
│ ├── build.sh # Build script
│ └── install.sh # Install script
├── build/ # Packaging and CI configurations
│ ├── package/ # Package configurations (Docker, AMI, etc.)
│ └── ci/ # CI configurations (Travis, CircleCI)
├── deployments/ # Deployment configurations and templates
│ └── kubernetes/ # Kubernetes deployment configs
├── test/ # Additional external test apps and data
│ └── data/ # Test data
├── docs/ # Design and user documents
│ └── architecture.md # Project architecture document
├── tools/ # Supporting tools for the project
│ └── mytool/ # Example tool directory
├── examples/ # Examples for applications and libraries
│ └── example_usage.go # Example usage of the public library
├── third_party/ # External helper tools and utilities
├── githooks/ # Git hooks
├── assets/ # Other assets (images, logos)
├── website/ # Project website data
│ └── index.html # Homepage for the project
├── go.mod # Go module file
└── go.sum # Go module dependency file

Characteristics:

  • Simplicity: A straightforward structure that organizes code without excessive complexity.
  • Single Layer of Abstraction: Common structures may not enforce strict layering like Onion or Clean architectures, leading to fewer abstractions.
  • Minimal Dependency Management: Less overhead in managing dependencies makes it easier to understand the project layout for newcomers.
  • Flexible Code Organization: Developers can organize code according to project needs rather than strict architectural guidelines, allowing for creative solutions.

Use Cases:

  • Small to Medium Projects: Ideal for smaller applications or projects where complexity is manageable and strict separation of concerns may be overkill.
  • Rapid Prototyping: Useful for quickly iterating on ideas without the overhead of maintaining a strict architectural framework.
  • Single-Developer Projects: Works well for individual developers who prefer a simple, less structured environment for building applications.
  • Learning and Experimentation: Suitable for beginners learning Go or those experimenting with new ideas, as it allows for exploration without getting bogged down by architectural decisions.

Conclusion

Choosing the right folder structure for your project is crucial and depends on several factors, including the size and complexity of the application, team collaboration, and future maintainability. The ideal structure should align with your specific needs and preferences, ensuring that it facilitates development and enhances the overall codebase organization.

It’s often beneficial to start with a simpler structure that meets your current requirements and refactor as the project evolves or if your needs change. This flexibility allows you to adapt to new challenges while maintaining a clear and manageable codebase.

References

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Bartu Kocakara
Bartu Kocakara

Written by Bartu Kocakara

Senior Software Developer @sixttr

No responses yet

Write a response