Backstage entity providers vs catalog locations: which one fits your catalog
Locations point the Backstage Software Catalog at specific files, while entity providers discover and sync entities from a source system. A location is the right tool when you can name the repositories or files that hold your catalog-info.yaml descriptors and those files change rarely. An entity provider is the right tool when the set of entities is defined by a source you can query, such as a Git organization, an identity directory or an internal inventory, and you want the catalog to follow that source as it grows and shrinks. Before building either, the platform team should decide where the source of truth for ownership lives, how many entities it will hold, and how quickly removed items must disappear from the portal.
The decision turns on deletion. Entities added through a registered or static location stay in the catalog until someone removes the location or the file, so a repository that is archived or deleted can leave stale entries behind unless someone cleans them up. Discovery providers reconcile against the source on each run, so an entity that no longer appears in the source is removed on a later pass, subject to the orphan handling settings your team chooses. Confirm the exact behavior of the provider and version you plan to run in the Backstage catalog documentation and in the provider's own reference, because delete semantics differ between providers and between configuration options.
Use locations for a small set of repositories where a person reviews each registration, and expect to maintain the list by hand. Plan for an entity provider once the number of repositories or records grows beyond what a team can register manually, or when entities must appear without a pull request in each owning repository. Before you start, confirm which providers exist for your source in your Backstage version, which credentials and scopes they need, how often they run, and who approves changes to the list of locations. The Backstage integrations documentation lists the source-control and directory options to check against your environment.
How registered locations, static locations and entity providers load entities
Backstage gives you three ways to put entities into the catalog: registered locations, static locations and discovery entity providers. All three hand their findings to the same processing pipeline, so the choice is about how entries are found, how often they are refreshed and how removals are noticed.
Registered locations through the API or UI
A registered location is a URL to a descriptor file that someone adds through the catalog API or the UI. The catalog reads that file on a schedule and keeps its entities until the location is unregistered. This suits a handful of repositories that teams add by hand. Check who is allowed to register locations, because the catalog accepts whatever URL a permitted user submits and the registration itself lives in the catalog database, not in Git.
Static locations defined in app-config
Static locations are listed in the app configuration file, so they load at startup and stay in place until someone edits the configuration and redeploys. Because the list is part of configuration in version control, changes are reviewed like any other code change. Confirm the exact catalog locations key in the catalog documentation for your Backstage version, and check that the app configuration is the only place that defines them so entries do not appear from two sources.
Discovery entity providers that scan an organization
Discovery entity providers, such as the GitHub or GitLab providers, query a source system for matching repositories and load a descriptor from each match. Nobody registers each repository by hand. The provider's filters decide what counts as a match, so review them with the platform team before turning the provider on. Expect a larger number of entities and more API calls per refresh, which makes the provider's schedule and rate limits part of the design.
One processing pipeline for every source
Whatever the source, the catalog runs the same processing steps: it reads the descriptor, runs processors that validate and enrich entities, and then writes the results to the catalog. Processors can change an entity but cannot remove one, so a rule that must block a bad entity belongs in validation before registration. Plan validation once for the pipeline, not separately for each source, so a descriptor behaves the same whichever way it arrived.
How each source notices removals
The mechanisms differ most in deletion. A registered or static location keeps its entities as long as the location exists, and removing the location removes its entities. A discovery provider deletes entities whose source record has disappeared on its next run, subject to the orphan strategy you set. Test a removal in a non-production catalog before you rely on it, because a missed deletion leaves stale owners and components visible to every user.
Refresh timing and source load
Registered and static locations are re-read on the catalog's processing schedule, so a change in a repository appears only after the next pass. Discovery providers add their own schedule on top of that and call the source API each time. Ask your platform team which API rate limits the source enforces, what the provider schedule is set to, and whether webhooks are available as an alternative to polling before you choose a provider for a large organization.
Which ingestion option fits which situation
This table compares registered locations, static locations and discovery entity providers on setup, discovery, refresh, change control and fit. Read the last rows first, because the right choice depends on whether the catalog is read-only and how many repositories must be found. Most organizations with many repositories end up with a discovery provider, while a small read-only catalog may use static locations alone.
| Factor | Registered or static location | Discovery entity provider |
|---|---|---|
| Setup effort | Low. Add one URL or file path per repository or descriptor in the app configuration or through the catalog API. | Higher. Configure the provider, credentials, scope filters and schedule, and confirm the discovery target before first run. |
| How new repositories are found | Not found automatically. Someone must add each location, or it must be listed in static config. | Found by scanning the source on each run, for example by matching a path pattern across an organization's repositories. |
| Refresh behavior | Re-read on the catalog's processing cycle for that location, so changes appear after the next pass. | Re-run on the provider's schedule, with the full or delta mutations defined by the provider implementation. |
| Deletion when a source is removed | Entities from a location that is removed are handled by orphan rules, so confirm the delete strategy before removing a location. | Entities whose source record disappears are removed by the provider's mutation logic, which makes the provider's scope and filters critical. |
| Who can change the catalog | Anyone who can edit the referenced file or the app configuration, so changes flow through reviewed config or Git. | Anyone who can commit a descriptor in a scanned repository, so repository access and branch protection define catalog change control. |
| Read-only catalog | Fits well. Static locations in configuration work with catalog read-only mode, and new components are added by config change. | Requires care. Confirm with the Backstage catalog documentation how the provider and read-only mode interact before relying on discovery. |
| Best fit: a handful of repositories | Good fit. Explicit listing is easy to review and audit. | Usually more setup than the benefit justifies. |
| Best fit: a single team | Good fit when the team owns a small, stable set of descriptors. | Fits when the team's repositories follow one naming or path convention. |
| Best fit: thousands of repositories | Impractical. Maintaining thousands of explicit entries becomes a configuration burden. | The usual choice, paired with strict scope filters and monitoring of run duration and rate limits. |
How each method handles deletion and orphaned entities
How an entity leaves the catalog depends on how it got there, so deleting one can mean very different things. A registered location is a pointer to a descriptor file that the catalog reads on each refresh. Unregistering the location removes the entities that came from it. A location declared in app-config.yaml cannot be unregistered through the API or UI. Removing it means changing configuration and redeploying. Confirm which of these paths your team uses before you plan any clean-up, because the two paths have different owners and different change controls.
Entities produced by an entity provider behave differently. The provider owns the set of entities it emits, so when a record disappears from the source, the next run of the provider should remove the matching entity. Removing the provider from configuration is a separate case. The entities it produced stop being maintained and are marked with the orphan annotation (backstage.io/orphan). What happens next is controlled by the orphan strategy settings, including the provider-level setting for a removed provider. Check the exact keys and defaults for your release in the orphan handling topic and the Backstage catalog documentation before you decide whether orphans should be deleted or kept.
The most common surprise is an entity that reappears after someone deletes it by hand. If the descriptor is still in a registered location, or the provider still returns the record, the next refresh recreates the entity. A manual delete only holds when the source is also cleared. Before you rely on any deletion path, run a test in a staging catalog: remove a descriptor file, remove a provider record, unregister a location, and remove a provider from configuration. For each case, record whether the entity is deleted, marked as an orphan or recreated, and how long the change takes to appear. Use the Backstage catalog documentation to confirm the processing behavior for your version.
Setting up entity ingestion for a small or large catalog
This sequence takes you from an inventory of your source repositories to a catalog that ingests them predictably, with each step closed by a check you can run. The result is a tested ingestion method per source, a refresh interval you can justify, and evidence that removals and orphans behave as expected before any team depends on the catalog.
Inventory sources and count repositories
Before choosing a mechanism, list every system that holds descriptors or service records, including the Git organizations, projects or groups that contain them, and an estimate of how many repositories each one holds. Note which repositories already contain a catalog-info.yaml file and which need one added. The platform team usually does this with the source owners, and the output is a short table of sources, counts and access owners. You know the inventory is complete when each source has a named owner and a count someone has verified against the platform's own view, not just a guess.
Choose the ingestion method per source
For each source, decide between a static or registered location that points at specific files, and a discovery entity provider that scans an organization or project and creates entities from what it finds. A few known repositories suit explicit locations, which are simple to review and easy to trace. Large or fast-changing estates suit discovery providers, which need a scan schedule, a filter and a clear rule for what happens when a file disappears. Record the choice and the reason beside each source. The check is a decision record that a second engineer can read and agree with.
Configure locations or providers in app-config
Add the chosen configuration to the backend section of app-config.yaml. Explicit locations go under catalog.locations, using the file or URL type for each descriptor. Discovery providers go under catalog.providers, with a filter or path pattern that limits the scan to the repositories you intend to include. Keep each source in its own named block so it can be changed without touching the others. Commit the change through your normal review process. The check is that the backend starts without configuration errors and the catalog's log output shows each provider or location being registered once.
Set refresh interval and source authentication
Set the refresh schedule for each provider, starting with a conservative interval that you can shorten later once you know the source's rate limits. Create a dedicated read-only credential for each source, scoped to the repositories in the filter, and store it in your secrets system rather than in plain configuration. Confirm the credential's scope with the source platform's administrator. The check is that a manual or first scheduled run completes without authentication errors and that the number of entities discovered matches the inventory from the first step within the range you expected.
Validate that a test entity appears
Create one throwaway test descriptor in a non-production repository with a unique metadata.name, a valid kind and owner, and a lifecycle value your catalog accepts. Wait for the next refresh or trigger a run, then search for the entity in the catalog UI and through the catalog API. Open its entity page and confirm the source location and owner display correctly. The check is that the test entity appears with the expected kind, owner and source, and that any validation warnings from processors are understood before you go further.
Test removal and orphan behavior
Remove the test descriptor from the repository, or move it out of the discovery filter, and run the provider again. Watch whether the entity is deleted, kept or marked as an orphan, and compare the result with the deletion and orphan settings you configured. Repeat the test for a removed provider configuration in a non-production environment if you plan to retire sources. Confirm with the catalog owners which behavior your organization wants before rollout. The check is a documented result for each test that matches the intended delete strategy, with no entity left in a state no one can explain.
Roll out source by source and monitor
Enable production ingestion one source at a time, starting with the least critical, and keep the configuration change for each source in its own commit so it can be reverted separately. After each source is live, check the entity count, the processing errors in the backend logs and the age of the most recent successful run. Add the monitoring signals you need for refresh failures and rate limit responses before adding the next source. The check is that each source has a stable entity count across two consecutive runs and that failures produce visible alerts or log entries your team reviews.
Choosing between locations and providers at different scales
When a small set of repositories has stable ownership, the simplest approach is usually a registered location or a static location pointing at each catalog-info.yaml file. The catalog reads those files on a schedule, and the operator can see exactly which sources are in use by reading the configuration. Refresh load on the source API is small because there are few files to fetch, and the cost of a full refresh is rarely a concern at this size. The trade-off is that every new repository requires a configuration change and a deployment, so the process depends on someone remembering to register it. Points to weigh:
- Configuration effort: each new repository is one more entry to add and review in version-controlled configuration.
- Deletion behavior: removing a location from configuration removes its entities, which makes the configuration the single source of truth.
- Refresh load: a few files fetched on the processing interval rarely strain the source platform.
- Ownership clarity: stable teams make it easy to assign a reviewer for each location.
- Growth signal: if registration requests start arriving every week, the set is outgrowing this method.
Confirm with your platform team how new repositories are requested and approved today, because that process will be the real bottleneck at this size.
Across several teams, a discovery entity provider for your Git platform usually fits better than hand-maintained locations. The provider searches for files matching a path or pattern and creates entities for each match, so teams add a descriptor to their repository without asking for a configuration change. Refresh load now depends on how many repositories the provider scans and how often it runs a full pass, so the schedule and filters matter more. Points to weigh:
- Discovery filters: narrow the search by organization, topic or path so the provider does not read repositories that were never meant for the catalog.
- Schedule choice: a full scan on a longer interval reduces API calls, while a shorter interval makes new entities appear sooner.
- Deletion behavior: when a descriptor disappears, the provider's deletion handling decides whether the entity is removed, so test this on a sample repository first.
- Rate limits: check what your Git platform allows for your authentication method and whether other tools share the same quota.
- Webhook option: if your platform supports events that signal a changed descriptor, these can replace repeated polling for freshness-sensitive entities.
Ask the provider's maintainers or your own tests which scan modes and deletion behaviors your installed version supports.
At thousands of repositories or in a large directory tenant, a full refresh of every source on each cycle can take long enough to delay updates and consume a large share of the source API quota. Teams in this position usually move to incremental ingestion, where the module fetches only changes since its last run, or to webhook-driven updates that process a change when the source reports it. A periodic full reconciliation still makes sense to catch missed events. Load now depends on change volume and the cost of each reconciliation, not only on the number of sources. Points to weigh:
- Incremental ingestion: the incremental ingestion module suits sources where changes can be queried by time or cursor, and it runs in bursts with rest periods between them.
- Webhooks: events reduce polling, but they need a reachable endpoint, signature checks and a way to recover missed deliveries.
- Reconciliation: a scheduled full pass corrects drift from lost events and from deletions the incremental path may not see.
- Monitoring: track ingestion progress and API responses so throttling shows up before entities go stale.
- Custom providers: an internal inventory with its own change feed may need a custom entity provider with full or delta mutations.
Before committing, confirm with the module's documentation which sources and versions it supports, and run a timed test against your real tenant size.
Security and access considerations for catalog sources
Every discovery provider and registered location is a path into your catalog, and each one carries credentials, trust decisions and a set of people who can change what the portal shows. The cards below cover the controls that matter most, in the order most teams hit them: the token that reads your repositories, who may add a location, what an untrusted source can inject, and how read-only settings shift the work to Git.
Least-privilege read tokens
A discovery provider reads your source control platform with a token or app credential, and that credential usually outlives the engineer who created it. Give the provider read-only access to the organizations and repositories it needs to discover, and nothing that writes. Confirm the exact scopes each provider requires in its own documentation, because the minimum set differs between GitHub, GitLab and Bitbucket. Store the credential in your secrets system rather than in a plain configuration file, and record which team owns it.
Rotating provider credentials
A credential that never rotates is a standing risk for the catalog, since anyone who obtains it can read every repository the provider can see. Set a rotation schedule for each discovery token or app secret, and plan the change so the new credential is deployed before the old one is revoked. Ask your provider whether it supports short-lived app installation tokens, which reduce how long a leaked value stays useful. Test rotation in a non-production Backstage instance first, so a missed update does not silently stop ingestion.
Who may register locations
In a catalog that accepts registrations from the UI or the API, any user with the right permission can point the catalog at a new file. Decide which roles may register locations, and whether registration is limited to the owning team's repositories. Review the registrations list regularly, because a location added by one person keeps feeding entities into the catalog until someone removes it. Pair this with the permission policy so that registration rights are granted deliberately, not inherited by default.
Untrusted repositories as sources
A location that points at a repository outside your control can publish entities with names, owners and annotations that look official. Illustratively, a fork of a team repository with a copied catalog-info.yaml could claim ownership of a production service and attract links and scorecards meant for the real team. Limit discovery to organizations you govern, check the repository host and branch a location reads, and review new locations from external sources before they enter the catalog.
Read-only catalog settings
When the catalog is set to read-only, the API no longer accepts entity changes, so Git becomes the only route for entities to enter or leave the catalog. This removes the registration risk above, but it moves the review burden to pull requests and to the branch protections on the repositories that hold descriptors. Confirm which plugins depend on writing to the catalog before you switch the setting, because they will stop working. Document how a team proposes a new entity so that reviewers know what they are approving.
Branch and file trust checks
Discovery providers typically read the default branch of each repository, so a change merged there becomes catalog data on the next run. Require review on the default branch of every repository that holds descriptors, and consider restricting which file paths the provider scans. Check how your provider handles files added through a feature branch or a merge request that is later closed, so that unreviewed content does not appear in the catalog. Confirm the exact matching behavior in the provider documentation.
Questions teams ask before choosing entity providers or locations
Do a few repositories justify a discovery entity provider?
Usually not on their own. For a handful of repositories, registering a few locations or committing catalog-info.yaml files directly is often simpler to review, debug and hand over. A provider starts to pay off when the number of sources grows, when new repositories appear often, or when you need removal behavior that follows the source automatically. Count how many entities you expect in twelve months and how often the list changes, then decide from those numbers rather than from the tool's capability alone.
How much more effort is a custom provider than registering locations?
Registering locations is mostly configuration and review: one entry per file or repository, plus a sign-off on each change. A custom entity provider adds code that reads the source, maps records to entities, schedules runs, handles errors and tests deletion. The build cost is one-time, but it recurs as the source API changes and as Backstage upgrades touch the catalog backend. Ask any partner to split the quote into the mapping logic, the scheduling and error handling, the tests, and the handover documentation.
What does the work need from our team?
You need someone who owns the source system, someone who knows the catalog model, and someone who can approve changes to the Backstage backend. For locations, the main input is a clear list of repositories and an agreed descriptor convention. For a provider, you also need API access to the source, a test or staging copy of it, a service account with the least permissions that work, and a named owner for the provider after handover. Confirm each of these before the scope is written.
Can our own engineers build and run this without a partner?
Yes, if your team has TypeScript and Backstage backend experience and time to maintain the code after go-live. Registered locations are within reach of most platform teams with the Backstage documentation. A custom provider needs more experience with catalog processing, the entity deletion model and upgrade testing. A partner is most useful when the team is small, the source is hard to query efficiently, or the deletion rules must be proven before anyone relies on them. Decide based on who will maintain the result for years.
How long does validation usually take in our environment?
It depends on the source, the number of entities, and how many teams must check their results. Validation covers descriptor checks, a dry run against a copy of real data, deletion tests where a record is removed from the source, and a review of how orphaned entities appear. Each of these needs data from your environment, so the timeline is set during scoping. Ask for the validation steps and their exit criteria in writing, and agree who signs off each one.
What drives the cost up or down?
The biggest drivers are the number of sources and entities, the quality of the source API (filtering, pagination, webhooks or rate limits), and how strict the deletion and ownership rules must be. Costs go down when descriptor conventions are settled early, when repositories already follow a template, and when the source team can expose a clean list endpoint. Costs go up when records lack stable identifiers, when ownership data is spread across systems, or when several teams must agree on rules late in the project. Ask for the cost drivers to be listed separately in the quote.
What goes wrong when a provider removes entities unexpectedly?
A provider that treats a failed or partial read as an empty source can delete many entities at once, which then disappear from the portal until the next successful run. Guard against this by checking record counts against a threshold, failing the run on errors, and testing what happens when the source is unreachable. Locations behave differently: removing a location from the configuration changes what is registered, so review those changes like code. Confirm the deletion behavior of your chosen approach in a staging catalog before production.
How DeployOpen works on this
DeployOpen starts with a written scope that decides which repositories and inventories feed the Backstage catalog and through which mechanism. We then build, test and document the provider configuration in your own infrastructure, so your team can run and change it after handover.
How we scope
- We inventory every source that should create entities, including repositories, cloud accounts and internal inventories.
- We record which sources need static locations and which need discovery entity providers, with the reason for each.
- We agree in writing how removed records should delete, orphan or persist, before any provider is configured.
How we build
- We configure registered and static locations for the small set of repositories that change rarely.
- We configure discovery providers with filters, schedules and organization data sources for larger estates.
- We test deletion behavior with a removed test repository and confirm the entities disappear as the scope states.
How we hand over
- We deliver the provider and location configuration as files kept in version control, with a written description of each source.
- We document the expected deletion behavior for each provider so reviewers can judge a change before it merges.
- We walk your platform and catalog owners through the configuration and the checks they should run after each change.
How we support
- Engagements are fixed-scope, with scope, deliverables and timelines agreed in writing before work starts.
- Ongoing support, upgrades and continuous testing are available as a retainer, covering provider changes after handover.
- Ask any partner to confirm which Backstage version your provider configuration targets and who owns each upgrade.

