Introduction
Composable secrets management, feature flags, and runtime configuration for Go.
Vault is a Go library that unifies secrets management, feature flags, and runtime configuration behind a single API surface. It encrypts secrets with AES-256-GCM, evaluates feature flags with rule-based targeting, and serves hot-reloadable config with per-tenant overrides.
Vault is a library -- not a service. You bring your own database, encryption key, and process lifecycle. Vault provides the plumbing.
What it does
- Encrypted secrets -- Store secrets encrypted with AES-256-GCM. Each value is encrypted at rest with a nonce-prefixed ciphertext and decrypted transparently on read.
- Auto-versioned secrets -- Every
Setcall auto-increments the version number and archives the previous value. Retrieve any historical version by number. - Feature flags -- Define boolean, string, int, float, and JSON flags with typed default values. The
flag.Serviceprovides type-safe accessors (Bool,String,Int,Float,JSON) that return the default on error. - Rule-based flag evaluation -- Target flags with
WhenTenant,WhenUser,Rollout(deterministic percentage),Schedule(time window),WhenTenantTag, andCustom(plugin-evaluated) rules. Rules are evaluated in priority order. - Runtime configuration -- Store typed config entries (
string,bool,int,float,json) with type-safe accessors andDurationparsing. RegisterWatchcallbacks that fire when a key is updated. - Per-tenant overrides -- The
override.Resolverchecks for a tenant-specific override before falling back to the app-level config value. Results are cached with a configurable TTL. - Secret rotation -- The
rotation.Managerruns a background loop checking policies for due rotations. Register aRotatorfunction per secret key and Vault handles scheduling, versioning, and record-keeping. - Audit logging -- The
audit.Loggerpersists append-only log entries with action, resource, outcome, and full scope context (app, tenant, user, IP). An optionalaudit_hook.Extensionforwards events to external systems. - Plugin system -- Register plugins that implement any combination of 8 capability interfaces:
OnInit,OnShutdown,SourceProvider,EncryptionProvider,FlagEvaluator,OnSecretAccess,OnConfigChange, andRotationStrategy. Theplugin.Registrydiscovers capabilities via type assertion at registration time. - Composable store backends -- Three backends implement the same composite
store.Storeinterface:memory(testing),postgres(pgx connection pool), andbun(Bun ORM). All support Migrate, Ping, and Close lifecycle methods.
Design philosophy
Library, not service. Vault is a set of Go packages you import. You control main, the database connection, the encryption key, and the process lifecycle.
Interfaces over implementations. Every subsystem defines a Go interface (secret.Store, flag.Store, config.Store, override.Store, rotation.Store, audit.Store). Swap any storage backend with a single type change.
Composable stores. The store.Store interface composes all six subsystem store interfaces. Pass a single backend value wherever a store is needed, or use different backends for different subsystems.
Tenant-scoped by design. The scope package injects app ID, tenant ID, user ID, and IP into context.Context. Every service, engine, and resolver reads scope from context -- cross-tenant data access is structurally impossible.
TypeID everywhere. All entities use type-prefixed, K-sortable, UUIDv7-based identifiers via id.ID. Passing a sec_ ID where a flag_ ID is expected fails at parse time.
Quick look
package main
import (
"context"
"fmt"
"log"
"github.com/xraph/vault/crypto"
"github.com/xraph/vault/flag"
"github.com/xraph/vault/scope"
"github.com/xraph/vault/secret"
"github.com/xraph/vault/store/memory"
)
func main() {
ctx := context.Background()
// 1. Create an in-memory store.
store := memory.New()
// 2. Set up AES-256-GCM encryption with a 32-byte key.
key := []byte("my-32-byte-secret-key-for-vault!") // exactly 32 bytes
enc, err := crypto.NewEncryptor(key)
if err != nil {
log.Fatal(err)
}
// 3. Create the secret service.
secretSvc := secret.NewService(store, enc, secret.WithAppID("myapp"))
// 4. Scope the context to a tenant.
ctx = scope.WithTenantID(ctx, "tenant-1")
// 5. Store and retrieve a secret.
meta, err := secretSvc.Set(ctx, "openai-api-key", []byte("sk-abc123"), "myapp")
if err != nil {
log.Fatal(err)
}
fmt.Printf("stored secret: id=%s version=%d\n", meta.ID, meta.Version)
sec, err := secretSvc.Get(ctx, "openai-api-key", "myapp")
if err != nil {
log.Fatal(err)
}
fmt.Printf("retrieved: %s\n", sec.Value)
// 6. Evaluate a feature flag.
engine := flag.NewEngine(store)
flagSvc := flag.NewService(engine, flag.WithAppID("myapp"))
enabled := flagSvc.Bool(ctx, "new-dashboard", false)
fmt.Printf("new-dashboard: %v\n", enabled)
}