MinIO — Structure#
Layout pattern#
Custom / Inverted Standard Go Layout
MinIO deviates from the canonical Go layout in a striking way: the entire application lives in a single cmd/ package (~453 Go files, package name cmd), with no traditional separation of handlers/services/repositories into sub-packages. The internal/ tree holds genuinely shared sub-libraries, but application logic is not layered — it is flat within cmd/. The root main.go is a thin wrapper that delegates immediately to cmd.Main(). There is no pkg/ directory; everything exported for the rest of the ecosystem lives in separate repositories (github.com/minio/pkg, etc.).
Directory map#
minio/
├── main.go # Root entry point — just calls cmd.Main(os.Args)
├── cmd/ # The entire application (~453 .go files, package "cmd")
│ ├── main.go # CLI app construction (minio server, fmtgen commands)
│ ├── server-main.go # Server bootstrap and initialization
│ ├── object-api-interface.go # ObjectLayer central interface
│ ├── erasure-*.go # Erasure coding engine (encode/decode, sets, pools)
│ ├── admin-handlers*.go # Admin API HTTP handlers
│ ├── bucket-*.go # Bucket lifecycle, policy, notification handlers
│ ├── iam-*.go # Identity and access management
│ ├── site-replication*.go # Cross-site replication
│ ├── batch-*.go # Batch job framework
│ ├── xl-storage*.go # Low-level disk storage layer
│ ├── testdata/ # Test fixtures (xl.meta, config files, etc.)
│ └── ...
├── internal/ # 34 internal sub-packages (shared libraries)
│ ├── amztime/ # AWS-compatible time formatting
│ ├── arn/ # Amazon Resource Name parsing
│ ├── auth/ # Credential types and signing
│ ├── bpool/ # Byte-slice buffer pool
│ ├── bucket/ # Bucket-policy sub-libraries
│ │ ├── bandwidth/ # Bandwidth throttling
│ │ ├── encryption/ # SSE configuration
│ │ ├── lifecycle/ # ILM lifecycle parsing
│ │ ├── object/ # Per-object lock
│ │ ├── replication/ # Replication config parsing
│ │ └── versioning/ # Bucket versioning config
│ ├── cachevalue/ # Generic timed-refresh cache
│ ├── color/ # Terminal colorisation
│ ├── config/ # Configuration subsystem
│ │ ├── api/ # S3 API knobs
│ │ ├── batch/ # Batch job config
│ │ ├── compress/ # Compression config
│ │ ├── dns/ # Federated DNS config
│ │ ├── etcd/ # etcd backend config
│ │ ├── heal/ # Healing config
│ │ ├── identity/ # IDP config (LDAP, OpenID)
│ │ ├── ilm/ # ILM (lifecycle) config
│ │ ├── lambda/ # Lambda / webhook config
│ │ ├── notify/ # Event notification config
│ │ ├── policy/ # Bucket policy config
│ │ ├── scanner/ # Background scanner config
│ │ ├── storageclass/ # STANDARD / RRS storage class
│ │ └── subnet/ # MinIO subnet config
│ ├── crypto/ # Encryption (SSE-C, SSE-S3, SSE-KMS)
│ ├── deadlineconn/ # Net conn with deadline
│ ├── disk/ # OS-level disk stats and info
│ ├── dsync/ # Distributed reader-writer mutex (quorum-based)
│ ├── etag/ # S3 ETag parsing and generation
│ ├── event/ # Event notification types and targets
│ ├── grid/ # Custom intra-cluster RPC (mux WebSocket)
│ ├── handlers/ # HTTP utility middleware
│ ├── hash/ # Content-hash reader/writer
│ ├── http/ # HTTP transport utilities
│ ├── init/ # Package-level init: sets TZ=UTC
│ ├── ioutil/ # Extended io utilities
│ ├── jwt/ # JWT parsing / validation
│ ├── kms/ # KMS abstraction (KES integration)
│ ├── lock/ # Local reader-writer lock with deadlock detection
│ ├── logger/ # Structured logger with audit support
│ ├── lsync/ # Local lock primitives
│ ├── mcontext/ # Request-scoped metadata context
│ ├── mountinfo/ # Mount point detection
│ ├── net/ # URL/host utilities
│ ├── once/ # Error-aware sync.Once
│ ├── pubsub/ # In-process pub/sub
│ ├── rest/ # HTTP REST client (admin API client)
│ ├── ringbuffer/ # Fixed-size ring buffer
│ ├── s3select/ # S3 Select (SQL over objects)
│ │ ├── csv/ # CSV parser
│ │ ├── json/ # JSON parser
│ │ ├── jstream/ # Streaming JSON tokeniser
│ │ ├── parquet/ # Parquet reader
│ │ ├── simdj/ # SIMD-accelerated JSON
│ │ └── sql/ # SQL parser/executor for S3 Select
│ └── store/ # Persistent event/WAL store
├── docs/ # Topic-specific documentation and shell test scripts
│ ├── distributed/ # Distributed mode setup + integration test scripts
│ ├── bucket/ # Lifecycle, replication, versioning shell tests
│ ├── iam/ # IAM policies and identity integration tests
│ ├── erasure/ # Erasure-coding documentation
│ └── ... # (24 topic subdirs total)
├── buildscripts/ # Build/CI helpers
│ ├── gen-ldflags.go # ldflags generation for version embedding
│ ├── cross-compile.sh # Cross-compilation helper
│ ├── race.sh # Race detector test runner
│ └── ...
├── dockerscripts/ # Docker entrypoint and utilities
├── helm/ # Helm chart for Kubernetes deployment
├── Dockerfile # Production Dockerfile (downloads pre-built binary)
├── Dockerfile.release # Multi-stage build: compile from source
├── Dockerfile.scratch # Minimal scratch-based image
├── Makefile # Primary build system
├── go.mod # Module root
└── main.go # Thin entry pointEntry points#
| File | Binary / Purpose |
|---|---|
main.go (root) | Sole binary entry point. Imports internal/init (TZ side-effect), then calls cmd.Main(os.Args). |
cmd/main.go | Registers two CLI commands (server, fmtgen) via github.com/minio/cli, then dispatches. |
cmd/server-main.go | The server subcommand — starts the full MinIO server (HTTP, erasure, IAM, etc.). |
cmd/fmtgen-main.go | fmtgen subcommand — a code-generation utility (not a server). |
MinIO produces one binary (minio). There is no cmd/ subdirectory tree with multiple binaries — cmd/ is a single package, not a directory of separate main packages.
Package organization#
Internal packages (
internal/): These are genuine shared libraries with clearly bounded responsibilities, extracted from the application core:internal/grid— custom cluster RPC layer (multiplexed WebSocket + typed message handlers)internal/dsync— distributed reader-writer mutex using quorum consensusinternal/crypto— SSE-C/SSE-S3/SSE-KMS encryption primitivesinternal/kms— KES (Key Encryption Service) abstractioninternal/event— S3 event notification types, targets (Kafka, NATS, Redis, etc.)internal/s3select— full S3 Select SQL engine over CSV/JSON/Parquetinternal/config/*— per-feature configuration structs and parsersinternal/bucket/*— S3 bucket-policy-related parsing (lifecycle, replication, versioning, WORM)internal/logger— structured logger with audit log supportinternal/auth— AWS-style credential types and signinginternal/bpool,internal/ioutil,internal/ringbuffer— low-level performance utilitiesinternal/init— forcesTZ=UTCvia package init side-effect (must be first import)
Public packages (
pkg/): None. MinIO has nopkg/directory. Reusable code that might benefit other consumers is published as separate Go modules undergithub.com/minio/pkg(external repository).Layering: MinIO does not follow clean architecture or hexagonal layering. The
cmd/package is the entire application — HTTP handlers, business logic, erasure engine, IAM, replication, and storage all coexist as peers within the same package. Theinternal/packages form a dependency ring aroundcmd/rather than being hierarchical layers within it.
Build system#
- Build tool: GNU Make (
Makefile) with Go toolchain - Key targets:
make build— standardgo build ./...; produces theminiobinarymake install— installs with race detectormake test— runs verifiers (lint + gen check) thengo test -tags kqueue,dev ./...make test-race— runs tests with-raceflag viabuildscripts/race.shmake crosscompile— cross-compiles for multiple targets viabuildscripts/cross-compile.shmake lint—golangci-lintwith custom.golangci.ymlmake check-gen— verifies_gen.gofiles are committed andgo.sumis cleanmake test-replication,make test-iam,make test-decom, etc. — integration test suites driven by shell scripts indocs/
- ldflags:
buildscripts/gen-ldflags.gogenerates version embedding at build time - Docker: Yes, multi-stage.
Dockerfile.releasecompiles from source (golang:1.24-alpine + ubi9/ubi-micro base).Dockerfile.releasealso downloadsmc(MinIO client).Dockerfileis a thin wrapper that pulls pre-built binaries fromdl.min.iofor production releases.Dockerfile.scratchproduces a minimal scratch image. EXPOSE 9000. - CI: GitHub Actions (
.github/workflows/) with jobs for: Go build (go.yml), cross-compilation (go-cross.yml), linting (go-lint.yml), healing tests (go-healing.yml), resiliency tests (go-resiliency.yml), IAM integrations (iam-integrations.yaml), Helm lint (helm-lint.yml).
Notable structural decisions#
Single-package application in
cmd/: Placing 453 Go files in one package namedcmdis architecturally unusual. It maximises cross-file access (no import cycles, no visibility barriers) at the cost of cohesion signalling. The team prioritises rapid development within the package over enforced module boundaries — a deliberate trade-off for a team that knows the codebase intimately.internal/as a surrounding utility ring: Rather than layering application logic into internal sub-packages, MinIO usesinternal/purely for extracted libraries (locking, networking, config parsing, s3select). The application-level code incmd/is not “on top of”internal/in a clean dependency hierarchy —cmd/imports liberally frominternal/but the logic boundary is blurry.No
pkg/— separate modules instead: Code intended for external use (e.g., credential types, CLI helpers, pkg utilities) is published as independent Go modules (github.com/minio/pkg,github.com/minio/cli,github.com/minio/madmin-go). This enforces a cleaner public API boundary than apkg/directory would.internal/initfor guaranteed global state: A dedicated package solely to setTZ=UTCviainit()is an unusual but robust pattern — it guarantees the side-effect fires before any other code, even across test binaries, as long as the import is present and first.Docs directory doubles as integration test runner: The
docs/directory is not just documentation — it contains shell scripts (e.g.,docs/distributed/decom.sh,docs/bucket/replication/setup_3site_replication.sh) that are the integration test suite, invoked bymake test-*targets. This blurs the line between documentation and testing infrastructure.Build tags for platform and dev modes: The test and build commands use
-tags kqueue,dev, indicating that certain code paths (kqueue I/O event notification on BSD/macOS, and adevbuild mode with additional instrumentation) are gated behind build tags — a structured way to handle platform variation and development-vs-production behavior differences.