Skip to main content 홈 크리에이터 marvinrichter clarc backstage-patterns
backstage-patterns Backstage patterns: Software Catalog (catalog-info.yaml, kinds, relations, lifecycle), TechDocs (MkDocs, techdocs-cli), Scaffolder templates (CSF3, steps, fetch:template, publish:github), custom plugins (frontend React, backend Express), GitHub App integration, and Chromatic CI.
설치로 이동 Skills Marketplace 커뮤니티가 만든 AI 스킬을 발견하고 탐색하세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/marvinrichter/clarc --skill backstage-patterns명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Zip 다운로드 다운로드 중... name backstage-patterns description Backstage patterns: Software Catalog (catalog-info.yaml, kinds, relations, lifecycle), TechDocs (MkDocs, techdocs-cli), Scaffolder templates (CSF3, steps, fetch:template, publish:github), custom plugins (frontend React, backend Express), GitHub App integration, and Chromatic CI.
Backstage Patterns
Reference for building and customizing Backstage — the open-source Internal Developer Portal from Spotify.
When to Activate
Creating or updating catalog-info.yaml for a service
Writing Backstage Scaffolder templates (Golden Paths)
Building a custom Backstage plugin
Setting up TechDocs for a service
Configuring GitHub App integration
Designing the software catalog entity model
Onboarding a new microservice into an existing Internal Developer Portal with team ownership and dependency tracking
Implementing a self-service workflow so developers can provision new services, databases, or queues through the Scaffolder UI
Migrating documentation from a wiki to TechDocs so it stays co-located with the code that it describes
Software Catalog
catalog-info.yaml — All Kinds
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: payment-service
description: Processes payments via Stripe
annotations:
[ , , ]
[ ]
[ ]
[]
[ , ]
backstage.io/techdocs-ref:
dir:.
github.com/project-slug:
myorg/payment-service
pagerduty.com/integration-key:
abc123def456
labels:
tier:
critical
tags:
typescript
stripe
postgres
spec:
type:
service
lifecycle:
production
owner:
group:payments-team
system:
ecommerce
dependsOn:
-
resource:payments-db
-
resource:stripe-integration
providesApis:
payment-api
consumesApis:
order-api
---
apiVersion:
backstage.io/v1alpha1
kind:
API
metadata:
name:
payment-api
spec:
type:
openapi
lifecycle:
production
owner:
group:payments-team
definition:
|
openapi: 3.0.0
info:
title: Payment API
version: v1
paths:
/payments:
post:
summary: Create payment
---
apiVersion:
backstage.io/v1alpha1
kind:
Resource
metadata:
name:
payments-db
description:
PostgreSQL
for
payment
records
spec:
type:
database
owner:
group:platform-team
system:
ecommerce
---
apiVersion:
backstage.io/v1alpha1
kind:
System
metadata:
name:
ecommerce
description:
The
e-commerce
platform
spec:
owner:
group:platform-team
domain:
commerce
---
apiVersion:
backstage.io/v1alpha1
kind:
Group
metadata:
name:
payments-team
spec:
type:
team
children:
members:
user:alice
user:bob
parent:
group:engineering
Relations Reference Relation Direction Example dependsOnComponent → Resource/Component service depends on database providesApisComponent → API service exposes this API consumesApisComponent → API service calls this API ownedByAny → Group team owns this service partOfComponent → System service is part of system hasMemberGroup → User user is on this team
Auto-Discovery
catalog:
providers:
github:
myorg:
organization: 'myorg'
catalogPath: '/catalog-info.yaml'
filters:
branch: 'main'
repository: '.*'
schedule:
frequency: { minutes: 30 }
timeout: { minutes: 3 }
Entity Lifecycle Management
metadata:
annotations:
backstage.io/orphan: 'true'
spec:
lifecycle: deprecated
TechDocs Documentation co-located with code, rendered in Backstage.
my-service/
catalog-info.yaml # Points to TechDocs
mkdocs.yml # MkDocs configuration
docs/
index.md # Required — root page
architecture.md
runbook.md
api-reference.md
site_name: Payment Service
site_description: Handles payments via Stripe
docs_dir: docs
nav:
- Home: index.md
- Architecture: architecture.md
- Runbook: runbook.md
- API: api-reference.md
plugins:
- techdocs-core
metadata:
annotations:
backstage.io/techdocs-ref: dir:.
npx @techdocs/cli serve
npx @techdocs/cli build
npx @techdocs/cli publish --publisher-type awsS3 \
--storage-name my-techdocs-bucket \
--entity default/component/payment-service
Scaffolder Templates (Golden Paths)
Template Anatomy
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: nodejs-rest-api
title: Node.js REST API
description: Production-ready Node.js API with Docker, CI/CD, and observability
tags: [nodejs , typescript , rest-api ]
spec:
owner: group:platform-team
type: service
parameters:
- title: Service Details
required: [name , description , owner ]
properties:
name:
type: string
pattern: '^[a-z][a-z0-9-]*[a-z0-9]$'
description: Lowercase, hyphens OK (e.g., order-processor)
description:
type: string
description: What does this service do?
owner:
type: string
ui:field: OwnerPicker
ui:options:
allowedKinds: [Group ]
- title: Infrastructure
properties:
database:
type: boolean
default: false
description: Provision a PostgreSQL database?
queue:
type: boolean
default: false
description: Provision an SQS queue?
- title: Repository
required: [repoUrl ]
properties:
repoUrl:
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts: [github.com ]
steps:
- id: fetch-template
name: Fetch Template
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
description: ${{ parameters.description }}
owner: ${{ parameters.owner }}
destination: ${{ parameters.repoUrl | parseRepoUrl }}
- id: publish-github
name: Create GitHub Repository
action: publish:github
input:
repoUrl: ${{ parameters.repoUrl }}
description: ${{ parameters.description }}
defaultBranch: main
gitCommitMessage: 'chore: initialize from golden path'
- id: register-catalog
name: Register in Catalog
action: catalog:register
input:
repoContentsUrl: ${{ steps['publish-github'].output.repoContentsUrl }}
catalogInfoPath: /catalog-info.yaml
- id: provision-db
name: Provision Database
if: ${{ parameters.database }}
action: github:actions:dispatch
input:
repoUrl: github.com?repo=infra&owner=myorg
workflowId: provision-db.yml
branchOrTagName: main
workflowInputs:
service_name: ${{ parameters.name }}
output:
links:
- title: Repository
url: ${{ steps['publish-github'].output.remoteUrl }}
- title: Open in Backstage
icon: catalog
entityRef: ${{ steps['register-catalog'].output.entityRef }}
Template Skeleton Files templates/nodejs-api/skeleton/
.github/workflows/
ci.yml # ${{ values.name }} — templated
src/
index.ts
app.ts
Dockerfile
catalog-info.yaml # Pre-filled with service metadata
package.json
README.md
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: ${{ values.name }}
description: ${{ values.description }}
spec:
type: service
lifecycle: experimental
owner: ${{ values.owner }}
Custom Plugins
Frontend Plugin
import { createPlugin, createRoutableExtension } from '@backstage/core-plugin-api' ;
import { rootRouteRef } from './routes' ;
export const myPlugin = createPlugin ({
id : 'my-plugin' ,
routes : {
root : rootRouteRef,
},
});
export const MyPluginPage = myPlugin.provide (
createRoutableExtension ({
name : 'MyPluginPage' ,
component : () => import ('./components/MyPluginPage' ).then (m => m.MyPluginPage ),
mountPoint : rootRouteRef,
}),
);
import React from 'react' ;
import { useEntity } from '@backstage/plugin-catalog-react' ;
import { InfoCard , Progress } from '@backstage/core-components' ;
import { useApi } from '@backstage/core-plugin-api' ;
export const MyPluginPage = ( ) => {
const { entity } = useEntity ();
const [data, setData] = React .useState (null );
React .useEffect (() => {
fetchData (entity.metadata .name ).then (setData);
}, [entity]);
if (!data) return <Progress /> ;
return (
<InfoCard title ="My Plugin" >
<pre > {JSON.stringify(data, null, 2)}</pre >
</InfoCard >
);
};
Backend Plugin
import { Router } from 'express' ;
import { PluginEnvironment } from '../types' ;
export async function createRouter (env : PluginEnvironment ): Promise <Router > {
const router = Router ();
router.get ('/health' , (_, res ) => res.json ({ status : 'ok' }));
router.get ('/entity/:name' , async (req, res) => {
const { name } = req.params ;
const entities = await env.catalog .getEntities ({
filter : [{ 'metadata.name' : name }],
});
res.json (entities.items [0 ] ?? null );
});
return router;
}
GitHub App Integration
integrations:
github:
- host: github.com
apps:
- appId: 12345
webhookUrl: https://backstage.mycompany.com/api/events/http/github-app-webhook
clientId: Iv1.abc123
clientSecret: ${GITHUB_APP_CLIENT_SECRET}
privateKey: ${GITHUB_APP_PRIVATE_KEY}
webhookSecret: ${GITHUB_APP_WEBHOOK_SECRET}
auth:
providers:
github:
development:
clientId: ${GITHUB_AUTH_CLIENT_ID}
clientSecret: ${GITHUB_AUTH_CLIENT_SECRET}
npx @backstage/create-github-app myorg
Production Configuration
app:
baseUrl: https://backstage.mycompany.com
backend:
baseUrl: https://backstage.mycompany.com
database:
client: pg
connection:
host: ${POSTGRES_HOST}
port: ${POSTGRES_PORT}
user: ${POSTGRES_USER}
password: ${POSTGRES_PASSWORD}
database: backstage
techdocs:
builder: external
publisher:
type: awsS3
awsS3:
bucketName: my-techdocs-bucket
region: us-east-1
accountId: '123456789'
Reference
platform-engineering — IDP strategy, maturity model, Team Topologies
visual-testing — Chromatic integration for Storybook-based component libraries