About using-backstage-backend-services
A skill for developers building or modifying Backstage backend plugins and modules. It helps select the appropriate core service and apply its usage patterns, including common implementation and testing pitfalls.
Key features
- 01Guidance for selecting core services
- 02Plugin and module service patterns
- 03Auth and cross-plugin HTTP guidance
- 04Scheduling and lifecycle practices
- 05Testing with mock services
Use cases
- 01Choosing services for a backend feature
- 02Adding dependencies to plugin registration
- 03Calling another plugin over HTTP
- 04Writing backend service tests
Install
Copy the command and run it in a terminal.
$
npx skills add https:/ / github.com/ vinzscam/ backstage-skills --skill using-backstage-backend-servicesAfter installing, type/using-backstage-backend-servicesin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
references/auth.mdcache.mddatabase.mdhttp-router.mdlogger-and-config.mdscheduler-and-lifecycle.mdurlReader-and-discovery.mdDetails
From the project READMEBackstage Backend Services
When to use this skill
- Plugin or module needs logging, configuration, HTTP routing, database, scheduling, caching, URL fetching, service discovery, or auth
- User mentions any specific
coreServices.*ref - Adding a new dep to a
register({ deps: {...} })block
Choose the right service
| Need | Service | Reference |
|---|---|---|
| Logging | coreServices.logger (plugin-scoped, pre-tagged with pluginId) | references/logger-and-config.md |
| Read app-config.yaml | coreServices.rootConfig | references/logger-and-config.md |
| Register HTTP routes | coreServices.httpRouter | references/http-router.md |
| Knex DB access | coreServices.database (plugin-scoped, isolated schema) | references/database.md |
| Periodic / cron tasks | coreServices.scheduler | references/scheduler-and-lifecycle.md |
| Startup / shutdown hooks | coreServices.lifecycle (plugin) or coreServices.rootLifecycle (root) | references/scheduler-and-lifecycle.md |
| Service-to-service tokens | coreServices.auth | references/auth.md |
| Authenticate incoming requests | coreServices.httpAuth | references/auth.md |
| Resolve current user from credentials | coreServices.userInfo | references/auth.md |
| Read external URLs (GitHub, GitLab, etc.) | coreServices.urlReader | references/urlReader-and-discovery.md |
| Resolve a backend plugin's base URL | coreServices.discovery | references/urlReader-and-discovery.md |
| Key-value cache | coreServices.cache | references/cache.md |
Two invocation modes
- Standalone: adding a service dep to an existing plugin or module.
- Post-scaffold (called by
creating-backstage-pluginfor backend templates): includecoreServices.loggerandcoreServices.httpRouteras defaults; surface additional services if intent suggests them (e.g. "stores X" → database; "polls every N minutes" → scheduler).
Common gotchas
- All refs come from
@backstage/backend-plugin-api. The actual implementations come from@backstage/backend-defaults, but plugins consume the refs only. - Plugin-scoped services give each plugin an isolated instance —
coreServices.databasereturns a Knex client scoped to a per-plugin schema;coreServices.loggeris pre-tagged withpluginId. Don't try to share a Knex instance across plugins by passing it around — call cross-plugin viacoreServices.discovery+ HTTP instead. - The
auth,httpAuth, anduserInfoservices are easy to confuse.authmints/verifies tokens for service-to-service calls;httpAuthauthenticates an incoming Express request;userInforesolves a user identity from credentials returned byhttpAuth. coreServices.schedulerschedules durable tasks across replicas — don't usesetIntervalfor production tasks.- For tests: use
mockServices.<name>(...)to get an instance for unit tests; usemockServices.<name>.factory(...)when passing tostartTestBackend({ features: [...] }). Not every service has a factory —httpRouter,cache,urlReader,lifecycleare typically provided by the test backend's defaults. - When calling another Backstage plugin via
discovery+auth(cross-plugin HTTP), handle non-OK responses withthrow await ResponseError.fromResponse(response)from@backstage/errors. It parses the response body for structured error info and produces a typed error other Backstage layers (logging, error reporting, frontend<ResponseErrorPanel>) understand. Never justthrow new Error(\Failed: ${response.status}`)`. - Inside route handlers, throw typed errors from
@backstage/errors(NotFoundError,InputError,NotAllowedError,ConflictError,ServiceUnavailableError,ForwardedError, etc.) — the default backend error middleware turns them into properly-formatted HTTP responses. Don'tres.status(...).json(...)for error cases. Seereferences/http-router.md.
Comments
Markdown supported