Concepts
Sentinel operates on a few core abstractions. Understanding these helps you reason about what the library does and why.
Metadata
Metadata is a normalized representation of a struct type. Where Go's reflect package gives you low-level access to type information, metadata gives you a structured view: the type's identity, its fields, and its relationships to other types.
Sentinel extracts metadata at two levels. Type metadata captures the struct as a whole—its name, package, and the graph of types it references. Field metadata captures each exported field—its name, type, kind, and struct tags.
Only exported fields are visible. Go's reflection cannot access unexported fields from outside their package, so sentinel doesn't try.
Type Identity
Every type has a fully qualified domain name (FQDN): the package path combined with the type name. For example, github.com/you/app/models.User.
FQDNs matter because type names alone aren't unique. Two packages can define a User type. The FQDN distinguishes them, and sentinel uses it as the cache key and in relationship references.
Relationships
Struct fields that reference other structs create relationships. Sentinel categorizes these into four kinds:
- Reference — a direct struct or pointer field (
Profile *Profile) - Collection — a slice or array of structs (
Orders []Order) - Embedding — an anonymous field (
BaseModel) - Map — a map with struct values (
Items map[string]Item)
Relationships are directional: they point from the containing type to the referenced type. Together, a set of relationships forms a type graph that you can traverse.
Field Kinds
Each field has a kind that categorizes its type for conditional logic: scalar, pointer, slice, struct, map, or interface. This lets you branch on the shape of a field without parsing type strings.
Immutability
Go's type system is fixed at compile time. A struct's fields, types, and tags cannot change while the program runs. Sentinel exploits this: once metadata is extracted, it never needs to be re-extracted or invalidated. The cache is permanent.
This also means the cache is global. There's one type system, so there's one metadata cache. No instance management, no lifecycle, no expiration.
Next Steps
- Architecture — internal design and implementation
- API Reference — complete type and function documentation