Purpose
Export and package Backstage plugins as RHDH dynamic plugins for deployment. This skill covers the build, export, and packaging workflow that transforms a developed plugin into a deployable artifact (OCI image, tgz archive, or npm package).
Note: This skill is for exporting and packaging already-implemented plugins. For creating new plugins, use the backend or frontend plugin creation skills first.
When to Use
Use this skill when you need to:
- •Export a plugin as a dynamic plugin package
- •Package a plugin as an OCI container image
- •Create a tgz archive for HTTP distribution
- •Publish a plugin to a container registry
- •Bundle multiple plugins into a single image
- •Generate integrity hashes for package verification
- •Troubleshoot export or packaging issues
Prerequisites
Before starting, ensure:
- •Plugin is built and compiles without errors (
yarn build) - •Container runtime installed (
podmanordocker) - •Access to a container registry (e.g., quay.io) if publishing OCI images
- •For backend plugins: Uses new backend system with default export
- •For frontend plugins: Has valid Scalprum configuration (auto-generated if not present)
Workflow Overview
- •Build Plugin - Compile TypeScript and verify no errors
- •Export as Dynamic Plugin - Create
dist-dynamic/with RHDH CLI - •Package as Artifact - Create OCI image, tgz, or npm package
- •Push to Registry - Publish to container or npm registry
- •Verify Locally - Test before deployment (optional)
Step 1: Build Plugin
Before exporting, ensure the plugin builds successfully:
cd plugins/<plugin-id> # or plugins/<plugin-id>-backend yarn build yarn tsc # Verify no TypeScript errors
Step 2: Export as Dynamic Plugin
Run the RHDH CLI export command from the plugin directory:
npx @red-hat-developer-hub/cli@latest plugin export
This creates a dist-dynamic/ directory containing:
- •Compiled JavaScript optimized for dynamic loading
- •Modified
package.jsonwith peer/bundled dependencies - •Config schema (if defined)
- •For frontend:
dist-scalprum/with webpack federated modules
Export Options
Control Shared Dependencies
By default, all @backstage/* packages are shared (provided by RHDH at runtime). Override this behavior:
# Bundle a @backstage package instead of sharing npx @red-hat-developer-hub/cli@latest plugin export \ --shared-package '!/@backstage/plugin-notifications/' # Mark a non-backstage package as shared npx @red-hat-developer-hub/cli@latest plugin export \ --shared-package @my-org/shared-utils
Embed Packages
Embed workspace or third-party packages into the plugin:
npx @red-hat-developer-hub/cli@latest plugin export \ --embed-package @my-org/plugin-common \ --embed-package @my-org/utils
Combined Example
npx @red-hat-developer-hub/cli@latest plugin export \ --shared-package '!/@backstage/plugin-notifications/' \ --embed-package @internal/common-utils
See references/export-options.md for all available options.
Step 3: Package as Artifact
Choose a packaging format based on your deployment needs.
OCI Image (Recommended for Production)
Create a container image:
npx @red-hat-developer-hub/cli@latest plugin package \ --tag quay.io/<namespace>/<plugin-name>:v0.1.0
Specify container tool if needed:
npx @red-hat-developer-hub/cli@latest plugin package \ --container-tool docker \ --tag quay.io/<namespace>/<plugin-name>:v0.1.0
Available tools: podman (default), docker, buildah
tgz Archive
Create a tar archive for HTTP distribution:
cd dist-dynamic npm pack
Get the integrity hash:
npm pack --json | jq -r '.[0].integrity'
npm Package
Publish to a private npm registry:
cd dist-dynamic npm publish --registry https://your-private-registry.com
Multi-Plugin Image
Bundle frontend and backend plugins in one image:
# Export both plugins first cd plugins/my-plugin && npx @red-hat-developer-hub/cli@latest plugin export cd ../my-plugin-backend && npx @red-hat-developer-hub/cli@latest plugin export # Package together from monorepo root cd ../.. npx @red-hat-developer-hub/cli@latest plugin package \ --tag quay.io/<namespace>/my-plugin-bundle:v0.1.0
See references/packaging-formats.md for detailed format comparison.
Step 4: Push to Registry
OCI Image
# Podman podman push quay.io/<namespace>/<plugin-name>:v0.1.0 # Docker docker push quay.io/<namespace>/<plugin-name>:v0.1.0
Private Registry Authentication
Set the auth file environment variable:
export REGISTRY_AUTH_FILE=~/.config/containers/auth.json # or export REGISTRY_AUTH_FILE=~/.docker/config.json
Image Digest
After pushing, get the digest for reproducible deployments:
podman inspect --format='{{.Digest}}' quay.io/<namespace>/<plugin-name>:v0.1.0
Use digest in dynamic-plugins.yaml:
plugins:
- package: oci://quay.io/<namespace>/<plugin-name>@sha256:abc123...!<plugin-id>-dynamic
disabled: false
Step 5: Verify Locally (Optional)
Test the exported plugin before publishing:
# Copy to local RHDH instance cp -r dist-dynamic /path/to/rhdh/dynamic-plugins-root/<plugin-id>-dynamic # Start RHDH and verify plugin loads yarn workspace backend start
Check logs for:
- •
loaded dynamic backend plugin- Success - •
Skipping disabled dynamic plugin- Plugin disabled in config - •Error messages during initialization
Configuration Examples
Backend Plugin
plugins:
- package: oci://quay.io/<namespace>/<plugin-name>:v0.1.0!<plugin-id>-backend-dynamic
disabled: false
pluginConfig:
myPlugin:
apiUrl: https://api.example.com
Frontend Plugin
plugins:
- package: oci://quay.io/<namespace>/<plugin-name>:v0.1.0!<plugin-id>
disabled: false
pluginConfig:
dynamicPlugins:
frontend:
my-org.plugin-my-plugin:
dynamicRoutes:
- path: /my-plugin
importName: MyPage
Multi-Plugin Bundle
plugins:
# Frontend from bundle
- package: oci://quay.io/<namespace>/my-bundle:v0.1.0!my-plugin
disabled: false
pluginConfig:
dynamicPlugins:
frontend:
my-org.plugin-my-plugin:
mountPoints:
- mountPoint: entity.page.overview/cards
importName: MyCard
# Backend from same bundle
- package: oci://quay.io/<namespace>/my-bundle:v0.1.0!my-plugin-backend-dynamic
disabled: false
See examples/dynamic-plugins.yaml for complete examples.
Troubleshooting
Export Fails
Missing dependencies:
yarn add -D <missing-package> npx @red-hat-developer-hub/cli@latest plugin export
TypeScript errors:
yarn tsc # Fix errors, then retry export
Clear stale artifacts:
rm -rf dist dist-dynamic yarn build npx @red-hat-developer-hub/cli@latest plugin export
Package Fails
Container tool not found:
# Specify available tool npx @red-hat-developer-hub/cli@latest plugin package \ --container-tool docker \ --tag quay.io/<namespace>/<plugin-name>:v0.1.0
Permission denied:
# Check registry login podman login quay.io
Plugin Not Loading in RHDH
- •Verify package path matches plugin ID
- •Check version compatibility with target RHDH
- •Ensure default export exists (backend plugins)
- •Verify Scalprum name matches (frontend plugins)
- •Check RHDH logs for specific errors
Integrity Hash Mismatch
Regenerate the hash:
cd dist-dynamic npm pack --json | jq -r '.[0].integrity'
Update dynamic-plugins.yaml with new hash.
Reference Files
- •
references/export-options.md- All export CLI options - •
references/packaging-formats.md- Format comparison and best practices - •
references/integrity-hashes.md- Hash generation and verification
Example Files
- •
examples/dynamic-plugins.yaml- Complete configuration examples