Gin — Structure#
Layout pattern#
Flat Library with Focused Sub-packages
Gin is a library, not a runnable service, so it has no cmd/ directory and no main.go. The core framework code lives directly in the root package (package gin), which is the most common pattern for Go libraries. Domain-specific concerns are delegated to focused sub-packages rather than a sprawling internal hierarchy. This is similar to the net/http stdlib approach: the root package is the public surface, sub-packages handle specializations.
Directory map#
gin/
├── *.go # Core framework (package gin): Engine, Context, RouterGroup,
│ # radix tree router, middleware, auth, recovery, logger, etc.
├── binding/ # Request body binding: JSON, XML, YAML, TOML, form, query,
│ # URI, header, multipart, protobuf, msgpack, BSON
├── codec/
│ └── json/ # Pluggable JSON backend selection: chooses between
│ # sonic, goccy/go-json, json-iterator, or stdlib encoding/json
├── render/ # Response rendering: JSON, XML, HTML templates, text, binary,
│ # protobuf, msgpack, TOML, YAML, redirect, PDF, SSE
├── ginS/ # Singleton convenience wrapper — wraps gin.Default() in a
│ # package-level instance for quick scripts / simple apps
├── internal/
│ ├── bytesconv/ # Zero-copy string↔[]byte helpers (unsafe, package-private)
│ └── fs/ # Filesystem abstraction (OnlyFilesFS) for Static serving
├── examples/ # Usage examples (not imported, for documentation only)
├── testdata/
│ ├── certificate/ # TLS cert/key for HTTPS tests
│ ├── protoexample/ # Proto-generated types for binding tests
│ └── template/ # HTML template files for render tests
├── docs/ # Minimal docs: doc.md (package godoc overview)
└── .github/
└── workflows/ # CI: gin.yml (test matrix), goreleaser.yml, codeql.yml, trivy-scan.ymlEntry points#
Gin has no binary entry points. There is no cmd/ directory and no main.go. The library is consumed by importing github.com/gin-gonic/gin. Users call gin.New() or gin.Default() to create an engine, register routes, and call engine.Run() or use it with http.ListenAndServe.
The ginS/ package provides a package-level singleton (var engine = sync.OnceValue(...)) as a convenience for minimal programs that want to skip explicit engine creation.
Package organization#
Internal packages:
internal/bytesconv— unsafe string-to-bytes conversions that avoid allocations; used in hot paths incontext.goandtree.gointernal/fs—OnlyFilesFSwrapper that prevents directory listing when serving static files
Public packages (pkg/): No
pkg/directory. All exported packages live as top-level sub-packages:binding— request body/form/query/URI parsing and validation; exposesBindingandStructValidatorinterfacesrender— response serialization; exposesRenderinterface implemented by ~12 format-specific typescodec/json— compile-time/runtime-switchable JSON encoder; abstractsencoding/json,json-iterator,sonic,goccy/go-jsonginS— singleton wrapper; depends only on the rootginpackage
Layering:
internal/*←gin(root) ←binding,render,codec/json(sub-packages used by the root)ginS←gin(root)- The layering is intentionally shallow: no clean-architecture layers, no separate domain/service/repository tiers. Gin is infrastructure, not a domain application.
Build system#
- Build tool:
make(Makefile at root) +goreleaserfor releases (.github/workflows/goreleaser.yml) - Key targets:
make test— runs tests acrossgin,ginS,binding,renderpackages with coverage collectionmake fmt/make fmt-check—gofmt -sformattingmake vet—go vetacross all packages except examplesmake lint—golintmake misspell/make misspell-checkmake tools— install golint and misspell
- Docker: No Dockerfile; gin is a library and ships no container
- CI: GitHub Actions (
gin.yml) runs the test matrix;goreleaser.ymlhandles tag-triggered releases;trivy-scan.ymldoes vulnerability scanning;codeql.ymldoes static security analysis
Notable structural decisions#
Core in root package. All of
Engine,Context,RouterGroup,HandlerFunc,tree, and built-in middleware (Logger,Recovery,BasicAuth) live in the rootginpackage. This makes the import path short (gin.Context,gin.Engine) and avoids package-name collisions, at the cost of a large root package (~25 source files).bindingandrenderas sibling sub-packages, not internal. These are exported sub-packages that users can import directly (e.g.,binding.JSON,render.JSON) and extend by implementing interfaces. Making them public enables custom binding backends and render targets without forking.codec/jsonas a build-tag-driven abstraction. Thecodec/jsonpackage uses a singleapi.gofile plus multiple backend files (sonic.go,go_json.go,jsoniter.go,json.go) where build tags or blank imports select the active backend at compile time. This is a deliberate performance optimization mechanism so users can swap JSON libraries without changing application code.ginSas an optional convenience layer. Rather than exposing global functions in the root package (which would pollute the main API and cause init-order issues), gin factored singleton behaviour into its own package. This is an unusual but tidy choice that keeps the core API clean.No vendor directory. Gin uses standard module mode with no vendoring, appropriate for a library that is itself a dependency. The go.sum file provides reproducibility.
Flat examples directory. Examples are not organized into sub-packages with
mainfunctions; the directory is a simple collection of standalone files or sub-directories browsed by users reading documentation. They are explicitly excluded frommake vet(VETPACKAGESfilters out/examples/).