Go-Projektstruktur: Best Practices & Patterns
Strukturieren Sie Ihre Go-Projekte für Skalierbarkeit und Klarheit
Die effektive Strukturierung eines Go-Projekts ist grundlegend für die langfristige Wartbarkeit, die Zusammenarbeit im Team und die Skalierbarkeit. Im Gegensatz zu Frameworks, die starre Verzeichnislayouts vorschreiben, schätzt Go Flexibilität – doch mit dieser Freiheit kommt die Verantwortung, Muster zu wählen, die den spezifischen Bedürfnissen Ihres Projekts dienen.

Gös Philosophie zur Projektstruktur verstehen
Gös minimalistische Designphilosophie erstreckt sich auch auf die Projektorganisation. Die Sprache schreibt keine bestimmte Struktur vor, sondern vertraut darauf, dass Entwickler fundierte Entscheidungen treffen. Dieser Ansatz hat dazu geführt, dass die Community mehrere bewährte Muster entwickelt hat, von einfachen flachen Layouts für kleine Projekte bis hin zu ausgefeilten Architekturen für Unternehmenssysteme.
Das Schlüsselprinzip lautet: Zunächst Einfachheit, Komplexität nur wenn notwendig. Viele Entwickler fallen in die Falle, ihre anfängliche Struktur zu überengineern, tief verschachtelte Verzeichnisse zu erstellen und vorzeitige Abstraktionen zu schaffen. Beginnen Sie mit dem, was Sie heute brauchen, und refaktorieren Sie, während Ihr Projekt wächst.
Wann sollte ich das Verzeichnis internal/ gegenüber pkg/ verwenden?
Das Verzeichnis internal/ erfüllt in Gös Design einen spezifischen Zweck: Es enthält Pakete, die von externen Projekten nicht importiert werden können. Gös Compiler erzwingt diese Einschränkung, was internal/ perfekt für private Anwendungslogik, Geschäftsregeln und Hilfsprogramme macht, die nicht außerhalb Ihres Projekts wiederverwendet werden sollen.
Das Verzeichnis pkg/ signalisiert hingegen, dass der Code für die externe Nutzung bestimmt ist. Platzieren Sie Code nur hier, wenn Sie eine Bibliothek oder wiederverwendbare Komponenten erstellen, die andere importieren möchten. Viele Projekte benötigen pkg/ überhaupt nicht – wenn Ihr Code nicht extern verbraucht wird, ist es sauberer, ihn im Stammverzeichnis oder in internal/ zu halten. Wenn Sie wiederverwendbare Bibliotheken erstellen, sollten Sie die Nutzung von Go-Generika in Betracht ziehen, um typsichere, wiederverwendbare Komponenten zu erstellen.
Das Standard-Go-Projektlayout
Das am weitesten verbreitete Muster ist das golang-standards/project-layout, obwohl es wichtig zu beachten ist, dass dies kein offizieller Standard ist. So sieht eine typische Struktur aus:
myproject/
├── cmd/
│ ├── api/
│ │ └── main.go
│ └── worker/
│ └── main.go
├── internal/
│ ├── auth/
│ ├── storage/
│ └── transport/
├── pkg/
│ ├── logger/
│ └── crypto/
├── api/
│ └── openapi.yaml
├── config/
│ └── config.yaml
├── scripts/
│ └── deploy.sh
├── go.mod
├── go.sum
└── README.md
Viele Teams halten ein kleines gemeinsames Logging-Paket unter internal/ (zum Beispiel internal/logx), sodass Binärdateien in cmd/ beim Start einen Logger einrichten; pkg/logger/ in der obigen Skizze ist nur dann angemessen, wenn dieser Code von anderen Modulen importiert werden soll. Für ein produktionsorientiertes log/slog-Setup (JSON-Zeilen, Redaktion, Kontext- und Trace-Felder und Signale, die gut mit Monitoring-Stacks zusammenspielen), siehe Strukturiertes Logging in Go mit slog für Observability und Alerting.
Das Verzeichnis cmd/
Das Verzeichnis cmd/ enthält Ihre Anwendungseinstiegspunkte. Jedes Unterverzeichnis stellt einen separaten ausführbaren Binärdatei dar. Zum Beispiel baut cmd/api/main.go Ihren API-Server, während cmd/worker/main.go einen Hintergrundjob-Prozessor bauen könnte.
Best Practice: Halten Sie Ihre main.go-Dateien minimal – nur genug, um Abhängigkeiten zu verbinden, Konfigurationen zu laden und die Anwendung zu starten. Alle wesentlichen Logiken gehören in Pakete, die main.go importiert.
// cmd/api/main.go
package main
import (
"log"
"myproject/internal/server"
"myproject/internal/config"
)
func main() {
cfg, err := config.Load()
if err != nil {
log.Fatal(err)
}
srv := server.New(cfg)
if err := srv.Start(); err != nil {
log.Fatal(err)
}
}
Das Verzeichnis internal/
Hier befindet sich Ihr privater Anwendungscode. Der Go-Compiler verhindert, dass externe Projekte Pakete innerhalb von internal/ importieren, was es ideal macht für:
- Geschäftslogik und Domänenmodelle
- Anwendungsdienste
- Interne APIs und Schnittstellen
- Datenbankanbindung (für die Auswahl der richtigen ORM, siehe unseren Vergleich von Go-ORMs für PostgreSQL)
- Authentifizierungs- und Autorisierungslogik
Organisieren Sie internal/ nach Feature oder Domäne, nicht nach technischer Schicht. Bevorzugen Sie statt internal/handlers/, internal/services/, internal/repositories/ lieber internal/user/, internal/order/, internal/payment/, wobei jedes Paket seine Handler, Dienste und Repositories enthält.
Sollte ich mit einer komplexen Verzeichnisstruktur beginnen?
Absolut nicht. Wenn Sie ein kleines Tool oder einen Prototyp erstellen, beginnen Sie mit:
myproject/
├── main.go
├── go.mod
└── go.sum
Wenn Ihr Projekt wächst und Sie logische Gruppierungen identifizieren, führen Sie Verzeichnisse ein. Sie könnten ein db/-Paket hinzufügen, wenn die Datenbanklogik substanziell wird, oder ein api/-Paket, wenn HTTP-Handler multiplizieren. Lassen Sie die Struktur natürlich entstehen, statt sie von vorneherein aufzuzwingen.
Flache vs. verschachtelte Strukturen: Das Gleichgewicht finden
Einer der häufigsten Fehler in der Go-Projektstruktur ist übermäßige Verschachtelung. Go bevorzugt flache Hierarchien – typischerweise eine oder zwei Ebenen tief. Tiefe Verschachtelung erhöht die kognitive Belastung und macht Imports umständlich.
Was sind die häufigsten Fehler?
Übermäßige Verschachtelung von Verzeichnissen: Vermeiden Sie Strukturen wie internal/services/user/handlers/http/v1/. Dies erzeugt unnötige Navigationskomplexität. Verwenden Sie stattdessen internal/user/handler.go.
Generische Paketnamen: Namen wie utils, helpers, common oder base sind Code-Smells. Sie vermitteln keine spezifische Funktionalität und werden oft zu Dumpinggrounds für unzusammenhängenden Code. Verwenden Sie beschreibende Namen: validator, auth, storage, cache.
Zirkuläre Abhängigkeiten: Wenn Paket A Paket B importiert und B Paket A, haben Sie eine zirkuläre Abhängigkeit – einen Kompilierungsfehler in Go. Dies signalisiert typischerweise eine schlechte Trennung der Belange. Führen Sie Schnittstellen ein oder extrahieren Sie gemeinsame Typen in ein separates Paket.
Mischen von Belangen: Halten Sie HTTP-Handler auf HTTP-Aspekte fokussiert, Datenbankanbindungen auf Datenzugriff und Geschäftslogik in Dienstpaketen. Das Platzieren von Geschäftsregeln in Handlern macht das Testen schwierig und koppelt Ihre Domänenlogik an HTTP.
Domain-Driven Design und Hexagonale Architektur
Für größere Anwendungen, insbesondere Microservices, bietet Domain-Driven Design (DDD) mit Hexagonaler Architektur eine klare Trennung der Belange.
Wie strukturiere ich einen Microservice gemäß Domain-Driven Design?
Die Hexagonale Architektur organisiert Code in konzentrischen Schichten, wobei die Abhängigkeiten nach innen fließen:
internal/
├── domain/
│ └── user/
│ ├── entity.go # Domänenmodelle und Value Objects
│ ├── repository.go # Repository-Schnittstelle (Port)
│ └── service.go # Domänendienste
├── application/
│ └── user/
│ ├── create_user.go # Use Case: Benutzer erstellen
│ ├── get_user.go # Use Case: Benutzer abrufen
│ └── service.go # Orchestrierung der Anwendungsdienste
├── adapter/
│ ├── http/
│ │ └── user_handler.go # HTTP-Adapter (REST-Endpunkte)
│ ├── postgres/
│ │ └── user_repo.go # Datenbankadapter (implementiert Repository-Port)
│ └── redis/
│ └── cache.go # Cache-Adapter
└── api/
└── http/
└── router.go # Routenkonfiguration und Middleware
Domänenschicht (domain/): Kerngeschäftslogik, Entitäten, Value Objects und Domänendienst-Schnittstellen. Diese Schicht hat keine Abhängigkeiten von externen Systemen – keine HTTP-, keine Datenbank-Imports. Sie definiert Repository-Schnittstellen (Ports), die Adapter implementieren.
Anwendungsschicht (application/): Use Cases, die Domänenobjekte orchestrieren. Jeder Use Case (z. B. “Benutzer erstellen”, “Zahlung verarbeiten”) ist eine separate Datei oder ein separates Paket. Diese Schicht koordiniert Domänenobjekte, enthält aber keine Geschäftsregeln selbst.
Adapterschicht (adapter/): Implementiert Schnittstellen, die von inneren Schichten definiert wurden. HTTP-Handler konvertieren Anfragen in Domänenobjekte, Datenbankanbindungen implementieren Persistenz, Message Queues handhaben asynchrone Kommunikation. Diese Schicht enthält allen Framework-spezifischen und Infrastrukturcode.
API-Schicht (api/): Routen, Middleware, DTOs (Data Transfer Objects), API-Versionierung und OpenAPI-Spezifikationen.
Diese Struktur stellt sicher, dass Ihre Kerngeschäftslogik testbar und unabhängig von Frameworks, Datenbanken oder externen Diensten bleibt. Sie können PostgreSQL durch MongoDB ersetzen oder REST durch gRPC, ohne den Domänencode zu berühren. Wenn Sie CQRS innerhalb dieses Layouts übernehmen, zeigt Implementierung von CQRS in Go wie die application/-Schicht natürlich auf separate Befehls- und Abfragehandler-Pakete abgebildet wird, wobei die Befehlsseite streng und die Abfrageseite DTO-orientiert bleibt.
Praktische Muster für verschiedene Projekttypen
Kleines CLI-Tool
Für Befehlszeilenanwendungen wünschen Sie eine Struktur, die mehrere Befehle und Unterbefehle unterstützt. Erwägen Sie die Verwendung von Frameworks wie Cobra für die Befehlsstruktur und Viper für das Konfigurationsmanagement. Unser Leitfaden zum Erstellen von CLI-Anwendungen in Go mit Cobra & Viper behandelt dieses Muster im Detail.
mytool/
├── main.go
├── command/
│ ├── root.go
│ └── version.go
├── go.mod
└── README.md
REST-API-Dienst
Beim Erstellen von REST-APIs in Go trennt diese Struktur die Belange klar: Handler handhaben HTTP-Aspekte, Dienste enthalten die Geschäftslogik und Repositories verwalten den Datenzugriff. Für einen umfassenden Leitfaden, der Standardbibliotheksansätze, Frameworks, Authentifizierung, Testmuster und produktionsreife Best Practices abdeckt, siehe unseren kompletten Leitfaden zum Erstellen von REST-APIs in Go. Für strukturiertes JSON-Logging, Anfrage- und Trace-Korrelation sowie Log-Formen, die Alerting unterstützen, siehe Strukturiertes Logging in Go mit slog für Observability und Alerting.
myapi/
├── cmd/
│ └── api/
│ └── main.go
├── internal/
│ ├── config/
│ ├── middleware/
│ ├── user/
│ │ ├── handler.go
│ │ ├── service.go
│ │ └── repository.go
│ └── product/
│ ├── handler.go
│ ├── service.go
│ └── repository.go
├── pkg/
│ └── httputil/
├── go.mod
└── README.md
Monorepo mit mehreren Diensten
myproject/
├── cmd/
│ ├── api/
│ ├── worker/
│ └── scheduler/
├── internal/
│ ├── shared/ # Gemeinsame interne Pakete
│ ├── api/ # API-spezifischer Code
│ ├── worker/ # Worker-spezifischer Code
│ └── scheduler/ # Scheduler-spezifischer Code
├── pkg/ # Gemeinsame Bibliotheken
├── go.work # Go-Arbeitsbereichsdatei
└── README.md
Testen und Dokumentation
Platzieren Sie Testdateien neben dem Code, den sie testen, mit dem Suffix _test.go:
internal/
└── user/
├── service.go
├── service_test.go
├── repository.go
└── repository_test.go
Diese Konvention hält Tests nahe an der Implementierung, was sie leicht auffindbar und wartbar macht. Für Integrationstests, die mehrere Pakete berühren, erstellen Sie ein separates test/-Verzeichnis im Projektstamm. Für umfassende Richtlinien zum Schreiben effektiver Unit-Tests, einschließlich tabelle-gesteuerter Tests, Mocks, Coverage-Analyse und Best Practices, siehe unseren Leitfaden zur Go-Unit-Test-Struktur und Best Practices.
Dokumentation gehört in:
README.md: Projektübersicht, Setup-Anweisungen, grundlegende Nutzungdocs/: Detaillierte Dokumentation, Architekturentscheidungen, API-Referenzenapi/: OpenAPI/Swagger-Spezifikationen, Protobuf-Definitionen
Für REST-APIs ist das Generieren und Bereitstellen von OpenAPI-Dokumentation mit Swagger entscheidend für die API-Entdeckbarkeit und das Entwicklererlebnis. Unser Leitfaden zum Hinzufügen von Swagger zu Ihrer Go-API behandelt die Integration mit beliebten Frameworks und Best Practices.
Abhängigkeiten mit Go-Modulen verwalten
Jedes Go-Projekt sollte Go-Module für das Abhängigkeitsmanagement verwenden. Für eine umfassende Referenz zu Go-Befehlen und Modulverwaltung, schauen Sie sich unser Go-Cheatsheet an. Initialisieren Sie mit:
go mod init github.com/yourusername/myproject
Dies erstellt go.mod (Abhängigkeiten und Versionen) und go.sum (Prüfsummen zur Verifizierung). Halten Sie diese Dateien unter Versionskontrolle für reproduzierbare Builds.
Aktualisieren Sie Abhängigkeiten regelmäßig:
go get -u ./... # Alle Abhängigkeiten aktualisieren
go mod tidy # Unbenutzte Abhängigkeiten entfernen
go mod verify # Prüfsummen verifizieren
Wichtige Erkenntnisse
-
Einfach beginnen, natürlich entwickeln: Überengineern Sie nicht Ihre anfängliche Struktur. Fügen Sie Verzeichnisse und Pakete hinzu, wenn die Komplexität es erfordert.
-
Flache Hierarchien bevorzugen: Begrenzen Sie die Verschachtelung auf eine oder zwei Ebenen. Gös flache Paketstruktur verbessert die Lesbarkeit.
-
Beschreibende Paketnamen verwenden: Vermeiden Sie generische Namen wie
utils. Benennen Sie Pakete nach dem, was sie tun:auth,storage,validator. -
Belange klar trennen: Halten Sie Handler auf HTTP fokussiert, Repositories auf Datenzugriff und Geschäftslogik in Dienstpaketen.
-
Nutzen Sie
internal/für Privatsphäre: Verwenden Sie es für Code, der nicht extern importiert werden sollte. Die meiste Anwendungslogik gehört hierher. -
Anwendungsarchitekturmuster bei Bedarf anwenden: Für komplexe Systeme bieten Hexagonale Architektur und DDD klare Grenzen und Testbarkeit.
-
Lassen Sie Go Sie führen: Folgen Sie Go-Idiomen, anstatt Muster aus anderen Sprachen zu importieren. Go hat seine eigene Philosophie der Einfachheit und Organisation.
Nützliche Links
- Go-Cheatsheet
- REST-APIs in Go erstellen: Kompletter Leitfaden
- CLI-Anwendungen in Go mit Cobra & Viper erstellen
- Go-Unit-Testing: Struktur & Best Practices
- Strukturiertes Logging in Go mit slog für Observability und Alerting
- Swagger zu Ihrer Go-API hinzufügen
- Go-Generika: Anwendungsfälle und Muster
- Vergleich von Go-ORMs für PostgreSQL: GORM vs Ent vs Bun vs sqlc
Andere verwandte Artikel
- Standard Go Project Layout - Community-getriebene Richtlinien zur Projektstruktur
- Go Modules Reference - Offizielle Go-Modul-Dokumentation
- Hexagonale Architektur in Go - Hexagonales Architekturframework für Unternehmensanwendungen
- Domain-Driven Design in Go - Produktionsreife DDD-Implementierung
- Go Project Structure Conventions - Zusätzliche Muster und Beispiele
- Effective Go - Offizieller Go-Best-Practices-Leitfaden
- App-Architektur-Hub — API-Design, Code-Struktur und Integrationsmuster