Skip to main content

Backstage Export CLI Usage Guide

The backstage-export CLI tool extracts entities from a running Backstage catalog for backup, migration, auditing, or analysis purposes. It connects directly to the Backstage API and can filter entities based on various criteria.

Table of Contents

Overview

The export CLI provides capabilities to:

  • Extract entities from Backstage catalog
  • Filter by kind, namespace, owner, tags, and more
  • Export for backup or migration
  • Audit catalog contents
  • Analyze entity relationships
  • Generate reports on catalog state

Key Features

  • Direct API Access: Connects to Backstage REST API
  • Flexible Filtering: Multiple filter criteria
  • Multiple Formats: YAML or JSON output
  • Batch Operations: Export multiple entity types
  • Manifest Generation: Track what was exported
  • Preview Mode: See what would be exported

Installation

From Source (Development)

# Clone the repository
git clone https://github.com/open-service-portal/ingestor.git
cd ingestor

# Install dependencies
yarn install

# Run directly with ts-node
npx ts-node src/cli/backstage-export.ts --help

Using Wrapper Script

From the portal-workspace:

# The wrapper script handles path resolution
../scripts/template-export.sh --kind Template

Global Installation (Future)

# Not yet published to npm
npm install -g @open-service-portal/backstage-plugin-ingestor
backstage-export --help

Authentication

No Authentication (Default)

For local development with guest access:

backstage-export --url http://localhost:7007 --kind Component

Bearer Token Authentication

For production Backstage instances:

# Using environment variable
export BACKSTAGE_TOKEN=your-token-here
backstage-export --kind Template

# Using command line option
backstage-export --token your-token-here --kind Template

# Using token from file
backstage-export --token "$(cat token.txt)" --kind Template

Obtaining a Token

Static Token (Development)

In app-config.local.yaml:

backend:
auth:
keys:
- secret: your-secret-key
externalAccess:
- type: static
options:
token: your-static-token

Service Account Token

# From Kubernetes service account
kubectl -n backstage get secret backstage-token -o jsonpath='{.data.token}' | base64 -d

GitHub Token (if configured)

Use a GitHub personal access token if Backstage uses GitHub auth.

Basic Usage

Export All Templates

backstage-export --kind Template

Export to Specific Directory

backstage-export --kind Component --output ./backup

Export Multiple Kinds

backstage-export --kind Template,Component,API

Preview Mode

backstage-export --kind Template --preview

List Mode

backstage-export --kind API --list

Command Options

Connection Options

OptionDescriptionDefault
-u, --url <url>Backstage API URLhttp://localhost:7007
-t, --token <token>Authentication token$BACKSTAGE_TOKEN
--timeout <ms>Request timeout30000
--retry <count>Retry failed requests3

Filter Options

OptionDescriptionDefault
-k, --kind <kinds>Entity kinds (comma-separated)Required
-n, --namespace <ns>Namespace filterAll namespaces
--name <pattern>Name pattern (supports wildcards)All names
--owner <owner>Owner filterAll owners
--tags <tags>Tags filter (comma-separated)All tags
--lifecycle <phase>Lifecycle phaseAll phases
--type <type>Entity type filterAll types

Output Options

OptionDescriptionDefault
-o, --output <dir>Output directory./exported
-f, --format <fmt>Output format (yaml/json)yaml
--single-fileExport all to one filefalse
--organizeOrganize by entity typefalse
--no-metadataExclude metadata fieldsfalse
--manifestGenerate export manifestfalse

Operation Modes

OptionDescriptionDefault
-p, --previewPreview without exportingfalse
-l, --listList entities onlyfalse
--countShow count onlyfalse
--statsShow statisticsfalse

Verbosity

OptionDescriptionDefault
--quietSuppress non-error outputfalse
--verboseShow detailed informationfalse
--debugShow debug informationfalse
--no-colorDisable colored outputfalse

Filtering Entities

By Kind

# Single kind
backstage-export --kind Template

# Multiple kinds
backstage-export --kind Template,Component,API

# All kinds (special value)
backstage-export --kind ALL

By Namespace

# Specific namespace
backstage-export --kind Component --namespace production

# Multiple namespaces (comma-separated)
backstage-export --kind Component --namespace "production,staging"

By Name Pattern

# Exact name
backstage-export --kind Template --name my-template

# Wildcard pattern
backstage-export --kind Component --name "service-*"

# Multiple patterns
backstage-export --kind Component --name "*-api,*-service"

By Owner

# Single owner
backstage-export --kind Component --owner platform-team

# Group owner
backstage-export --kind Component --owner "group:platform-team"

# User owner
backstage-export --kind Component --owner "user:john.doe"

By Tags

# Single tag
backstage-export --kind Template --tags crossplane

# Multiple tags (AND logic)
backstage-export --kind Template --tags "crossplane,production"

# Tag with value
backstage-export --kind Component --tags "env:production"

By Type

# Service components
backstage-export --kind Component --type service

# Library components
backstage-export --kind Component --type library

# XRD templates
backstage-export --kind Template --type crossplane-xrd

Combined Filters

# Production services owned by platform team
backstage-export \
--kind Component \
--type service \
--namespace production \
--owner platform-team \
--tags "tier:1"

Output Formats

Default Structure

backstage-export --kind Template
# Creates:
# ./exported/templates.yaml (or templates.json)

Organized Structure

backstage-export --kind Template,Component --organize
# Creates:
# ./exported/Template/template1.yaml
# ./exported/Template/template2.yaml
# ./exported/Component/component1.yaml
# ./exported/Component/component2.yaml

Single File

backstage-export --kind Template,Component --single-file
# Creates:
# ./exported/entities.yaml (contains all entities)

With Manifest

backstage-export --kind Template --manifest
# Creates:
# ./exported/templates.yaml
# ./exported/manifest.json

Manifest example:

{
"timestamp": "2024-01-15T10:30:00Z",
"source": "http://localhost:7007",
"filters": {
"kind": ["Template"]
},
"statistics": {
"total": 15,
"byKind": {
"Template": 15
}
},
"entities": [
{
"kind": "Template",
"namespace": "default",
"name": "xdnsrecord"
}
]
}

Use Cases

1. Backup and Recovery

#!/bin/bash
# backup-catalog.sh

DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="./backups/catalog_$DATE"

# Export all critical entities
backstage-export \
--url https://backstage.example.com \
--token "$BACKSTAGE_TOKEN" \
--kind Template,Component,System,Domain,API \
--output "$BACKUP_DIR" \
--organize \
--manifest

# Compress backup
tar -czf "$BACKUP_DIR.tar.gz" "$BACKUP_DIR"
rm -rf "$BACKUP_DIR"

echo "Backup created: $BACKUP_DIR.tar.gz"

2. Migration Between Instances

# Export from source
backstage-export \
--url https://old-backstage.example.com \
--token "$OLD_TOKEN" \
--kind ALL \
--output ./migration \
--organize

# Import to target (using separate import tool or API)
for file in ./migration/**/*.yaml; do
curl -X POST https://new-backstage.example.com/api/catalog/entities \
-H "Authorization: Bearer $NEW_TOKEN" \
-H "Content-Type: application/yaml" \
--data-binary "@$file"
done

3. Audit and Compliance

# Generate audit report
backstage-export \
--kind Component \
--list \
--stats > audit-report.txt

# Export components missing owners
backstage-export \
--kind Component \
--output ./audit/no-owner \
--filter '!metadata.owner'

# Export production components
backstage-export \
--kind Component \
--lifecycle production \
--output ./audit/production \
--manifest

4. Template Analysis

# Export all Crossplane templates
backstage-export \
--kind Template \
--type crossplane-xrd \
--output ./crossplane-templates

# Analyze template usage
backstage-export \
--kind Template \
--stats \
--verbose | grep "Usage count"

5. CI/CD Integration

# .github/workflows/backup-catalog.yml
name: Backup Catalog
on:
schedule:
- cron: '0 2 * * *' # Daily at 2 AM

jobs:
backup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '18'

- name: Install Export Tool
run: npm install -g @open-service-portal/backstage-plugin-ingestor

- name: Export Catalog
env:
BACKSTAGE_TOKEN: ${{ secrets.BACKSTAGE_TOKEN }}
run: |
backstage-export \
--url https://backstage.example.com \
--kind ALL \
--output ./catalog-backup \
--manifest

- name: Upload Backup
uses: actions/upload-artifact@v3
with:
name: catalog-backup-${{ github.run_id }}
path: ./catalog-backup
retention-days: 30

Examples

Basic Examples

# Export all templates
backstage-export --kind Template

# Export with preview
backstage-export --kind Component --preview

# List all APIs
backstage-export --kind API --list

# Export to JSON
backstage-export --kind System --format json

# Custom output directory
backstage-export --kind Domain --output ./domains

Advanced Examples

# Export production services
backstage-export \
--kind Component \
--type service \
--lifecycle production \
--output ./prod-services \
--organize

# Export with full filtering
backstage-export \
--url https://backstage.example.com \
--token "$TOKEN" \
--kind Template,Component \
--namespace default \
--owner platform-team \
--tags "managed,v2" \
--output ./filtered-export \
--manifest

# Generate statistics report
backstage-export \
--kind ALL \
--stats \
--count \
--verbose > catalog-stats.txt

# Export for documentation
backstage-export \
--kind API \
--format json \
--no-metadata \
--output ./api-docs

# Incremental export (new entities only)
backstage-export \
--kind Component \
--filter 'metadata.createdAt>2024-01-01' \
--output ./new-components

Real-World Scenarios

Scenario 1: Disaster Recovery Setup

#!/bin/bash
# disaster-recovery.sh

# Full catalog export
echo "Starting full catalog backup..."

backstage-export \
--url "$BACKSTAGE_URL" \
--token "$BACKSTAGE_TOKEN" \
--kind ALL \
--output ./dr-backup \
--organize \
--manifest

# Verify export
if [ -f ./dr-backup/manifest.json ]; then
TOTAL=$(jq '.statistics.total' ./dr-backup/manifest.json)
echo "Successfully exported $TOTAL entities"
else
echo "Export failed!"
exit 1
fi

# Create recovery script
cat > ./dr-backup/restore.sh << 'EOF'
#!/bin/bash
# Restore script for catalog entities

BACKSTAGE_URL=${1:-http://localhost:7007}
TOKEN=${2:-}

for file in */**.yaml; do
echo "Importing $file..."
curl -X POST "$BACKSTAGE_URL/api/catalog/entities" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/yaml" \
--data-binary "@$file"
done
EOF

chmod +x ./dr-backup/restore.sh
tar -czf dr-backup-$(date +%Y%m%d).tar.gz ./dr-backup

Scenario 2: Catalog Synchronization

#!/bin/bash
# sync-catalogs.sh

SOURCE_URL="https://backstage-prod.example.com"
TARGET_URL="https://backstage-staging.example.com"

# Export from production
echo "Exporting from production..."
backstage-export \
--url "$SOURCE_URL" \
--token "$PROD_TOKEN" \
--kind Template,System,Domain \
--output ./sync-temp \
--organize

# Transform if needed (example: change owner)
find ./sync-temp -name "*.yaml" -exec sed -i 's/owner: prod-team/owner: staging-team/g' {} \;

# Import to staging
echo "Importing to staging..."
for file in ./sync-temp/**/*.yaml; do
curl -X POST "$TARGET_URL/api/catalog/entities" \
-H "Authorization: Bearer $STAGING_TOKEN" \
-H "Content-Type: application/yaml" \
--data-binary "@$file" \
--silent --output /dev/null
done

echo "Synchronization complete"
rm -rf ./sync-temp

Scenario 3: Ownership Audit

#!/bin/bash
# ownership-audit.sh

echo "Catalog Ownership Audit Report"
echo "=============================="
echo ""

# Export all components
backstage-export \
--kind Component \
--output ./audit-temp \
--quiet

# Analyze ownership
echo "Components by Owner:"
echo "-------------------"
grep -h "owner:" ./audit-temp/*.yaml | sort | uniq -c | sort -rn

echo ""
echo "Components without owners:"
echo "-------------------------"
grep -L "owner:" ./audit-temp/*.yaml | wc -l

echo ""
echo "Orphaned components (no owner field):"
echo "------------------------------------"
for file in ./audit-temp/*.yaml; do
if ! grep -q "owner:" "$file"; then
basename "$file" .yaml
fi
done

# Cleanup
rm -rf ./audit-temp

Troubleshooting

Connection Issues

# Test connection
curl -I http://localhost:7007/api/catalog/entities

# Check with token
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:7007/api/catalog/entities?limit=1

# Verbose mode for debugging
backstage-export --kind Template --debug

Authentication Errors

# Verify token is set
echo $BACKSTAGE_TOKEN

# Test token directly
curl -H "Authorization: Bearer $BACKSTAGE_TOKEN" \
http://localhost:7007/api/catalog/entities

# Try without token (guest access)
backstage-export --kind Template --token ""

No Entities Found

# Check available kinds
backstage-export --kind ALL --list

# Try without filters
backstage-export --kind Component

# Use debug mode
backstage-export --kind Template --debug

# Check API directly
curl http://localhost:7007/api/catalog/entities?filter=kind=Template

Performance Issues

# Export in batches by namespace
for ns in default production staging; do
backstage-export --kind Component --namespace "$ns" --output "./export-$ns"
done

# Limit fields exported
backstage-export --kind Component --no-metadata

# Increase timeout for large catalogs
backstage-export --kind ALL --timeout 60000

Export Validation

# Validate exported YAML
for file in exported/*.yaml; do
yq eval '.' "$file" > /dev/null || echo "Invalid: $file"
done

# Check entity structure
yq eval '.kind, .metadata.name' exported/templates.yaml

# Verify manifest
jq '.statistics' exported/manifest.json

Environment Variables

# Backstage URL
export BACKSTAGE_URL=https://backstage.example.com
backstage-export --kind Template

# Authentication token
export BACKSTAGE_TOKEN=your-token-here
backstage-export --kind Component

# Default output directory
export BACKSTAGE_EXPORT_DIR=./my-exports
backstage-export --kind API

# Debug mode
export BACKSTAGE_DEBUG=true
backstage-export --kind System

Best Practices

  1. Use Preview First: Always preview before large exports
  2. Filter Appropriately: Don't export ALL unless necessary
  3. Organize Large Exports: Use --organize for many entities
  4. Include Manifests: Use --manifest for audit trail
  5. Secure Tokens: Never commit tokens to version control
  6. Validate Exports: Check exported files are valid YAML/JSON
  7. Incremental Backups: Export only changed entities when possible
  8. Document Filters: Record what filters were used for exports

API Compatibility

The export tool is compatible with:

  • Backstage v1.0+
  • Catalog API v1
  • Both alpha and stable API endpoints

For older Backstage versions, use appropriate API paths:

# Legacy API path
backstage-export --url http://localhost:7007/catalog

See Also