Backstage Catalog
The Backstage Catalog domain tests the entity model, descriptor files, registration locations, processing and validation, and the relations that connect services, APIs, systems, and teams. It is the data backbone of the developer portal.
Entity model
Catalog entities use apiVersion: backstage.io/v1alpha1 and a kind, with metadata.name as the stable identifier. Core kinds include Component, API, Resource, System, Domain, Group, User, Location, and Template. A Component typically declares spec.type (for example service), spec.lifecycle, spec.owner, and optional links to a system, providesApis, consumesApis, and dependsOn. Names must follow the catalog's DNS-like rules: lowercase alphanumerics and hyphens, starting and ending alphanumeric. Owners must resolve to a Group or User entity.
Locations and processing
Entities enter through a Location, usually a catalog-info.yaml file registered by URL or listed in catalog.locations. The URL reader fetches the descriptor; built-in processors validate the kind and shape, apply defaults, and emit relations. Relation names are directional and processor-generated: ownedBy, partOf, hasPart, providesApi, consumesApi, dependsOn, and dependencyOf. The catalog records backstage.io/managed-by-location and backstage.io/managed-by-origin-location annotations to show where an entity came from. catalog.rules controls which kinds are allowed; location rules can restrict kinds per location.
Worked example
You register a Component named payments with spec.owner: team-payments, spec.system: payments-platform, and spec.providesApis: [payments-api]. The owner Group must already exist or be registered in the same processing cycle; the System and API must also resolve. After processing, the catalog shows ownedBy to team-payments, partOf to payments-platform, and providesApi to payments-api. If the owner is missing, the entity may be ingested but the relation is unresolved and the catalog reports an error; validation and relation resolution are separate stages.
Traps
Do not put owner under metadata; it belongs in spec. Do not use uppercase, underscores, or spaces in metadata.name. Do not hand-write relations like ownedBy; they are derived from fields such as spec.owner. Do not expect a catalog-info.yaml filename to be mandatory-any descriptor can be registered, though that name is conventional. Do not assume dependsOn takes a bare name; use the entity reference form kind:namespace/name when needed.