Vault — Structure#

Layout pattern#

Custom / Monorepo with in-tree sub-modules

Vault does not follow the conventional Go community layout (cmd/, pkg/, internal/). Instead it uses a domain-driven top-level layout where each major concern gets its own directory. Two subdirectories (api/ and sdk/) are published as independent Go modules (with their own go.mod) while living in the same repository tree and connected via replace directives in the root go.mod. A separate ui/ directory contains a full Ember.js frontend. The result is a monorepo with multiple module boundaries — a pattern common among large HashiCorp projects.

Directory map#

vault/                          ← root binary entry point (main.go)
├── api/                        ← independent Go module: Go client library (github.com/hashicorp/vault/api)
│   ├── auth/                   ← auth helper subpackages (approle, aws, etc.)
│   ├── cliconfig/              ← CLI configuration helpers
│   └── tokenhelper/            ← token helper abstraction
├── audit/                      ← audit backend implementations (file, socket, syslog)
├── builtin/                    ← all built-in plugins compiled into the binary
│   ├── credential/             ← auth methods: approle, aws, cert, github, ldap, okta, radius, token, userpass
│   ├── logical/                ← secret engines: aws, consul, database, nomad, pki, pkiext, rabbitmq, ssh, totp, transit
│   └── plugin/                 ← generic plugin backend (delegates to external plugin process)
├── command/                    ← CLI command implementations (vault <subcommand>)
│   ├── agent/                  ← vault agent end-to-end tests
│   ├── agentproxyshared/       ← shared code between agent and proxy
│   ├── config/                 ← HCL config file parsing for agent/proxy
│   ├── healthcheck/            ← health check command logic
│   ├── proxy/                  ← vault proxy command
│   ├── server/                 ← vault server command and server config parsing
│   └── token/                  ← token file helpers
├── helper/                     ← internal utility packages (not exported as SDK)
│   ├── builtinplugins/         ← registry: maps plugin names to factory functions
│   ├── fairshare/              ← work queue with fairness scheduling
│   ├── identity/               ← protobuf types for identity entities/groups
│   ├── metricsutil/            ← Prometheus/dogstatsd metrics helpers
│   ├── namespace/              ← namespace context helpers
│   ├── testhelpers/            ← large test helper package for integration tests
│   └── ... (20+ utility packages)
├── http/                       ← HTTP handler layer (mux registration, middleware)
│   └── priority/               ← request priority/limiting middleware
├── internal/                   ← strictly internal packages (Go convention enforced)
│   └── observability/          ← OTEL tracing helpers
├── internalshared/             ← packages shared between main module and sdk (unusual split)
│   ├── configutil/             ← shared config parsing utilities
│   └── listenerutil/           ← TLS listener configuration helpers
├── limits/                     ← request rate and resource limiting
├── physical/                   ← storage backend implementations
│   ├── aerospike/              ← Aerospike backend
│   ├── azure/                  ← Azure Blob Storage backend
│   ├── cassandra/              ← Cassandra backend
│   ├── consul/                 ← Consul KV backend
│   ├── dynamodb/               ← DynamoDB backend
│   ├── etcd/                   ← etcd backend
│   ├── gcs/                    ← Google Cloud Storage backend
│   ├── postgresql/             ← PostgreSQL backend
│   ├── raft/                   ← Integrated Raft (HashiCorp raft) backend — the default
│   ├── s3/                     ← AWS S3 backend
│   └── ... (15+ storage backends)
├── plugins/                    ← (thin) plugin catalog support
├── sdk/                        ← independent Go module: plugin development SDK (github.com/hashicorp/vault/sdk)
│   ├── database/               ← database plugin protocol (dbplugin)
│   ├── framework/              ← high-level framework for writing Vault backends
│   ├── helper/                 ← 40+ utility packages for plugin authors
│   ├── logical/                ← core interfaces: Backend, Storage, Request, Response
│   ├── physical/               ← storage interface + file/inmem reference implementations
│   ├── plugin/                 ← plugin client/server (go-plugin RPC wrapper)
│   ├── queue/                  ← priority queue for credential rotation
│   └── rotation/               ← automated secret rotation helpers
├── serviceregistration/        ← service discovery backends
│   ├── consul/                 ← Consul service registration
│   └── kubernetes/             ← Kubernetes service registration
├── shamir/                     ← Shamir's Secret Sharing implementation (for unseal)
├── tools/                      ← developer tooling (codechecker, semgrep, stubmaker)
├── ui/                         ← Ember.js frontend application (separate npm project)
├── vault/                      ← core server logic (Core struct, router, token store, policy store…)
│   ├── activity/               ← client activity / billing log
│   ├── cluster/                ← HA cluster coordination
│   ├── diagnose/               ← vault operator diagnose
│   ├── eventbus/               ← internal event pub/sub (for event notifications API)
│   ├── plugincatalog/          ← runtime plugin catalog management
│   ├── quotas/                 ← request/rate/lease quotas
│   ├── seal/                   ← seal/unseal logic (autounseal, shamir)
│   └── tokens/                 ← token store helpers
├── version/                    ← version string package
└── website/                    ← MDX documentation source (published to developer.hashicorp.com)

Entry points#

FileBinaryPurpose
main.govaultSingle binary entry point; delegates immediately to command.Run()
command/main.go(package, not standalone)Implements Run() / RunCustom() — CLI dispatcher using hashicorp/cli
command/server/(subcommand)vault server — starts the Vault server process
command/agent/(subcommand)vault agent — starts Vault Agent (auto-auth + template rendering)
command/proxy/(subcommand)vault proxy — starts Vault Proxy (API proxy with caching)

There is a single compiled binary. All modes (server, agent, proxy, CLI) are subcommands of that binary.

Package organization#

  • Internal packages: vault/ (core), helper/, http/, internal/, internalshared/, command/, audit/, physical/, serviceregistration/, builtin/, limits/, shamir/
  • Public packages (published as sub-modules):
    • sdk/ — plugin development SDK; sdk/logical defines Backend, Storage, Request, Response; sdk/framework provides a high-level helper for writing backends
    • api/ — Go client library; intended for both CLI and third-party integration
  • Layering:
    • Bottom layer: sdk/logical (interfaces only) + sdk/physical (storage interface)
    • Implementation layer: vault/ (Core, router, token/policy stores), physical/ backends, audit/ backends
    • Plugin layer: builtin/credential/ and builtin/logical/ implement sdk/logical.Backend
    • HTTP layer: http/ wraps vault/Core in an HTTP server
    • CLI layer: command/ uses api/ client to communicate with the HTTP layer
    • This is a strict layered architecture: the sdk module has no dependency on the main module; plugins can be developed without access to vault internals.

Build system#

  • Build tool: GNU Make (Makefile) + custom shell scripts (scripts/build.sh)
  • Key targets:
    • make dev — builds a development binary to ./bin/vault with testonly build tag
    • make bin — builds release binary with UI assets embedded
    • make dev-ui — builds dev binary with UI assets
    • make test — runs all unit tests across main, sdk, and api packages
    • make fmt — runs gofmt on all non-generated Go files
  • Build tags used: testonly (enables test-only code paths), ui (embeds web UI), foundationdb (enables CGO + FoundationDB backend), minimal (strips non-core backends)
  • Docker: Yes, multi-stage — the Dockerfile uses Alpine as the final stage and accepts BIN_NAME, PRODUCT_VERSION, TARGETARCH build args, pulling pre-built binaries from HashiCorp’s release infrastructure (not building from source inside Docker)
  • CI: GitHub Actions (.github/workflows/); Enos framework (enos/) for integration/acceptance testing across cloud environments

Notable structural decisions#

  1. Three Go modules in one repo: The root module (github.com/hashicorp/vault), sdk/ (github.com/hashicorp/vault/sdk), and api/ (github.com/hashicorp/vault/api) are all separate modules connected by replace directives during development. This allows sdk and api to be imported by third-party plugin authors without pulling in the full Vault server and its 300+ dependencies.

  2. vault/ package shadows the repo root: The most important package is vault/vault/ (import path github.com/hashicorp/vault/vault). Naming the core package the same as the project while placing it in a subdirectory is unusual but deliberate — it prevents the core from being the root package, keeping main.go thin.

  3. physical/ has 20+ storage backends compiled in: Unlike many projects that rely on external plugins for storage, Vault compiles all storage backends directly into the binary and selects at runtime via config. This avoids deployment complexity at the cost of binary size.

  4. internalshared/ is an unusual seam: Packages shared between the root module and the sdk module (but not meant for external use) live in internalshared/ rather than in either module’s internal/ directory — a pragmatic workaround for Go’s internal/ visibility rules across module boundaries.

  5. helper/testhelpers/ is a massive test infrastructure package: Rather than scattered test helpers, a large consolidated package at helper/testhelpers/ provides cluster creation, unsealing, replication setup, and more. This reflects how deeply integration-tested Vault is — test infrastructure is first-class code.

  6. Enterprise/CE split accommodated by build stubs: Files like command/server/server_stubs_oss.go and vault/logical_system_fields_stubs_oss.go use the oss naming convention to provide no-op implementations of enterprise features in the community edition, enabling the enterprise branch to swap in real implementations without #ifdef-style conditionals.