Claude-skill-registry backstage-backend-plugin
Build Backstage backend plugins with createBackendPlugin and core services: DI, httpRouter, secure-by-default auth, Knex DB, routes, testing. Use for APIs and background jobs.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/backstage-backend-plugin" ~/.claude/skills/majiayu000-claude-skill-registry-backstage-backend-plugin && rm -rf "$T"
skills/data/backstage-backend-plugin/SKILL.mdBackstage Backend Plugin (New Backend System)
About This Skill
This skill provides specialized knowledge and workflows for building Backstage backend plugins using the New Backend System. It guides the development of server-side functionality including REST/HTTP APIs, background jobs, data processing, and integrations.
What This Skill Provides
- Specialized workflows - Step-by-step procedures for creating and configuring backend plugins
- Best practices - Production-ready patterns for auth, validation, error handling, and database usage
- Golden path templates - Copy/paste code snippets for common backend patterns
- Domain expertise - Backstage-specific knowledge about DI, core services, and secure-by-default architecture
When to Use This Skill
Use this skill when creating server-side functionality for Backstage: REST/HTTP APIs, background jobs, data processing, or integrations.
Development Workflow
Phase 1: Planning and Research
1.1 Understand the Requirements
Before building a backend plugin, clearly understand:
- What endpoints or APIs are needed (REST, GraphQL, webhooks)
- What data storage requirements exist (database, cache)
- Whether background jobs or scheduled tasks are needed
- Authentication and authorization requirements
- Integration points with other services or plugins
1.2 Load Reference Documentation
Load reference files as needed based on the plugin requirements:
For Core Services:
- ⚙️ Core Services Reference - Comprehensive guide to all core backend services including:
- httpRouter, logger, database, httpAuth, userInfo
- cache, scheduler, urlReader, discovery, permissions
- Usage patterns and best practices for each service
For Testing:
- ✅ Testing Reference - Comprehensive testing guide for backend plugins
Phase 2: Implementation
Follow the Golden Path workflow below for implementation, referring to reference files as needed.
Important Decisions:
- Determine which core services are needed (load ⚙️ Core Services Reference)
- Plan database schema and migrations if using database
- Design authentication policies (which endpoints need auth?)
- Plan error handling and validation strategies
Phase 3: Testing
After implementing the plugin:
- Load the ✅ Testing Reference
- Write comprehensive tests for:
- Router endpoints using
startTestBackend - Database operations with
TestDatabases - External service calls with MSW (Mock Service Worker)
- Authentication flows
- Router endpoints using
- Run tests and achieve good coverage:
yarn backstage-cli package test --coverage
Phase 4: Review and Polish
Before publishing:
- Run linting and structure checks
- Ensure proper error handling throughout
- Verify authentication policies are correct
- Check database migrations are production-ready
- Review the Common Pitfalls section below
- Test horizontal scalability (no in-memory state)
Quick Facts
- Scaffold with
→ backend‑plugin; the package lives inyarn new
.plugins/<id>-backend/ - Define the plugin with
, declare dependencies viacreateBackendPlugin
, and initialize indeps
.register(env).registerInit - Attach routes through
. Backstage prefixes plugin routers withcoreServices.httpRouter
./api/<pluginId> - Backends are secure by default; use
to allow unauthenticated endpoints likehttpRouter.addAuthPolicy({ path, allow })
./health - Core services (logger, database, httpRouter, httpAuth, userInfo, urlReader, scheduler, etc.) are available via
.coreServices
Production Best Practices
Request Validation
Validate inputs at the edge using a schema (e.g., zod) before hitting DBs or external services:
import { z } from 'zod'; const querySchema = z.object({ q: z.string().min(1) }); router.get('/search', async (req, res, next) => { const parsed = querySchema.safeParse(req.query); if (!parsed.success) return res.status(400).json({ error: 'invalid query' }); try { // ... perform work with parsed.data.q res.json({ items: [] }); } catch (e) { next(e); } });
Error Handling
Add a terminal error handler to your router and prefer structured logs with context:
import { errorHandler } from '@backstage/backend-common'; router.use(errorHandler());
Auth and Identity
-
Keep backends secure-by-default
-
Open only explicit paths with
addAuthPolicy -
For protected routes, extract credentials with
httpAuth -
Derive user/entity identity via
when requireduserInfo// Inside a route handler const creds = await httpAuth.credentials(req, { allow: ['user', 'service'] }); const { userEntityRef } = await userInfo.getUserInfo(creds); logger.info('request', { userEntityRef });
Database Usage
- Use
to get a database clientconst knex = await database.getClient(); - Keep queries in small repo/service modules
- Write migrations in JavaScript (
) and export them in package.json (see Core Services Reference for details).js
Observability & Scalability
- Avoid in-memory state
- Make handlers idempotent
- Log with
for traceabilitylogger.child({ plugin: 'example' })
Golden Path (Copy/Paste Workflow)
1) Scaffold
# From the repository root (interactive) yarn new # Select: backend-plugin # Plugin id (without -backend suffix), e.g. example # Non-interactive (for AI agents/automation) yarn new --select backend-plugin --option pluginId=example --option owner=""
This creates
plugins/example-backend/ using the New Backend System with createBackendPlugin.
2) src/plugin.ts
— plugin + DI + router
src/plugin.tsimport { createBackendPlugin, coreServices } from '@backstage/backend-plugin-api'; import { createRouter } from './service/router'; export const examplePlugin = createBackendPlugin({ pluginId: 'example', register(env) { env.registerInit({ deps: { httpRouter: coreServices.httpRouter, logger: coreServices.logger, database: coreServices.database, // optional httpAuth: coreServices.httpAuth, // optional userInfo: coreServices.userInfo, // optional }, async init({ httpRouter, logger, database, httpAuth, userInfo }) { const router = await createRouter({ logger, database, httpAuth, userInfo }); httpRouter.use(router); // Secure-by-default: open /health only httpRouter.addAuthPolicy({ path: '/health', allow: 'unauthenticated' }); }, }); }, }); export { examplePlugin as default } from './plugin';
Key points: DI via
deps, register routes with the plugin’s httpRouter, and export the plugin as the default. (Backstage)
3) src/service/router.ts
— minimal Express router
src/service/router.tsimport express from 'express'; import type { LoggerService, DatabaseService, HttpAuthService, UserInfoService, } from '@backstage/backend-plugin-api'; export interface RouterOptions { logger: LoggerService; database?: DatabaseService; httpAuth?: HttpAuthService; userInfo?: UserInfoService; } export async function createRouter(options: RouterOptions): Promise<express.Router> { const { logger } = options; const router = express.Router(); router.get('/health', (_req, res) => { logger.info('health check'); res.json({ status: 'ok' }); }); return router; }
4) Add to your backend
In
packages/backend/src/index.ts:
const backend = createBackend(); backend.add(import('@internal/plugin-example-backend')); backend.start();
Now
GET http://localhost:7007/api/example/health returns { "status": "ok" }. (Backstage)
5) Database, auth, identity (when needed)
- Database: depend on
to get a Knex client; create your own migrations and run them via your chosen process. (Backstage)coreServices.database - Identity: use
+coreServices.httpAuth
to obtain the calling user and their entity refs when an endpoint needs identity. (Backstage)coreServices.userInfo - Core services catalog: consult the Backstage Core Backend Service APIs for the full list (cache, scheduler, urlReader, etc.). (Backstage)
Verify in a Backstage backend
- Add the plugin to
viapackages/backend/src/index.ts
.backend.add(import('@internal/plugin-<id>-backend')) - Start the repo (e.g.,
at the root). Then check:yarn start- GET http://localhost:7007/api/example/health →
{ "status": "ok" } - If 401 occurs, ensure you opened
with/health
.addAuthPolicy
- GET http://localhost:7007/api/example/health →
Testing, linting & structure checks
Use Backstage's CLI for tests and lints:
yarn backstage-cli package test yarn backstage-cli package lint yarn backstage-cli repo lint
Keep routers small (
/service/router.ts), inject dependencies (DB, auth, clients) from plugin.ts, and avoid in-memory state (horizontally scalable).
Common Pitfalls (and Fixes)
| Problem | Solution | Reference |
|---|---|---|
404s under | Remember Backstage prefixes plugin routers with | Backstage |
| Auth unexpectedly required | Backends are secure by default; open endpoints explicitly via | Backstage |
| Tight coupling | Never call other backend code directly; communicate over the network or through well-defined services | Backstage |
Reference Files
📚 Documentation Library
Load these resources as needed during development:
Core Services
- ⚙️ Core Services Reference - Complete guide to all core backend services including:
- HTTP Router Service for route registration
- Logger Service for structured logging
- Database Service for Knex-based data access
- HTTP Auth Service and User Info Service for authentication
- Cache Service for key-value storage
- Scheduler Service for background tasks
- Discovery Service for inter-plugin communication
- URL Reader Service for reading external content
- Permissions Service for authorization
- Configuration and health check services
- Service composition examples and best practices
Testing
- ✅ Testing Reference - Comprehensive testing guide including:
- Testing backend plugins with
startTestBackend - Mock services for all core services
- Testing routers with supertest
- Testing authentication and permissions
- External service mocking with MSW
- Database testing with
TestDatabases - Service factory testing
- Integration testing patterns
- Best practices and common patterns
- Testing backend plugins with
External References
- Backend plugins: scaffolding, DI,
,httpRouter
, secure‑by‑default, DB & identity usage. (Backstage)/api/<pluginId> - Core Backend Service APIs index (logger, database, httpAuth, scheduler, urlReader, etc.). (Backstage)
- Anthropic Skill spec & packaging details (required metadata; ≤200 char description). (Claude Help Center)