Claude Code Plugins

Community-maintained marketplace

Feedback

backstage-backend-plugin

@rothenbergt/backstage-agent-skills
1
0

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.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name backstage-backend-plugin
description 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.
version 1.0.0
license Complete terms in LICENSE.txt

Backstage 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

  1. Specialized workflows - Step-by-step procedures for creating and configuring backend plugins
  2. Best practices - Production-ready patterns for auth, validation, error handling, and database usage
  3. Golden path templates - Copy/paste code snippets for common backend patterns
  4. 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:


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:

  1. Load the ✅ Testing Reference
  2. Write comprehensive tests for:
    • Router endpoints using startTestBackend
    • Database operations with TestDatabases
    • External service calls with MSW (Mock Service Worker)
    • Authentication flows
  3. Run tests and achieve good coverage:
    yarn backstage-cli package test --coverage
    

Phase 4: Review and Polish

Before publishing:

  1. Run linting and structure checks
  2. Ensure proper error handling throughout
  3. Verify authentication policies are correct
  4. Check database migrations are production-ready
  5. Review the Common Pitfalls section below
  6. Test horizontal scalability (no in-memory state)

Quick Facts

  • Scaffold with yarn new → backend‑plugin; the package lives in plugins/<id>-backend/.
  • Define the plugin with createBackendPlugin, declare dependencies via deps, and initialize in register(env).registerInit.
  • Attach routes through coreServices.httpRouter. Backstage prefixes plugin routers with /api/<pluginId>.
  • Backends are secure by default; use httpRouter.addAuthPolicy({ path, allow }) to allow unauthenticated endpoints like /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 userInfo when required

    // 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 const knex = await database.getClient(); to get a database client
  • Keep queries in small repo/service modules
  • Write migrations in JavaScript (.js) and export them in package.json (see Core Services Reference for details)

Observability & Scalability

  • Avoid in-memory state
  • Make handlers idempotent
  • Log with logger.child({ plugin: 'example' }) for traceability

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.

(Backstage)

2) src/plugin.ts — plugin + DI + router

import { 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

import 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 coreServices.database to get a Knex client; create your own migrations and run them via your chosen process. (Backstage)
  • Identity: use coreServices.httpAuth + coreServices.userInfo to obtain the calling user and their entity refs when an endpoint needs identity. (Backstage)
  • 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 packages/backend/src/index.ts via backend.add(import('@internal/plugin-<id>-backend')).
  • Start the repo (e.g., yarn start at the root). Then check:

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 /api Remember Backstage prefixes plugin routers with /api/<pluginId> Backstage
Auth unexpectedly required Backends are secure by default; open endpoints explicitly via httpRouter.addAuthPolicy 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

External References

  • Backend plugins: scaffolding, DI, httpRouter, /api/<pluginId>, secure‑by‑default, DB & identity usage. (Backstage)
  • 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)