Skip to content

Export Tools

github-actions[bot] edited this page Jul 6, 2026 · 11 revisions

Using the Dynamic Plugins Export Tools

This guide covers the CLI tools and workflow options for exporting Backstage plugins as dynamic plugins.


Overview

The export process transforms a standard Backstage plugin into an OCI-packaged dynamic plugin that can be loaded at runtime by a Backstage-based host application.

Source Plugin                     Export Process                    OCI Artifact
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ package.jsonβ”‚    β”‚ 1. Clone source repo           β”‚    β”‚ Dynamic plugin       β”‚
β”‚ src/        │───▢│ 2. Apply patches               │───▢│ packaged as OCI      β”‚
β”‚ ...         β”‚    β”‚ 3. Install dependencies        β”‚    β”‚ image                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚ 4. Build plugin                β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β”‚ 5. Export as dynamic plugin    β”‚
                   β”‚ 6. Package as OCI container    β”‚
                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

CLI Package

The export tooling is provided by the @red-hat-developer-hub/cli package (specified in versions.json):

Component Version
Backstage 1.52.0
Node.js 24.14.0
CLI @red-hat-developer-hub/cli@1.10.7
# Install/run the CLI
npx @red-hat-developer-hub/cli@1.10.7 plugin export

πŸ“– Version Matrix: Ensure CLI version matches your target platform version. See versions.json for current values.


Export Arguments in plugins-list.yaml

Each plugin entry in plugins-list.yaml can include CLI arguments after the colon:

plugins/my-plugin:
plugins/my-plugin-backend: --embed-package @backstage/some-dependency --suppress-native-package cpu-features

CLI Arguments Quick Reference

Argument Description
--embed-package <pkg> Bundle a dependency into the dynamic plugin (for packages not available separately)
--shared-package <pkg> Mark package as shared (provided by host at runtime)
--shared-package '!<pkg>' Force a @backstage/ package to be bundled instead of shared
--suppress-native-package <pkg> Exclude a native Node.js package from the bundle

πŸ“– Full CLI Documentation: For comprehensive details on all export flags, shared vs embedded dependencies, and frontend plugin configuration, see: Export Derived Dynamic Plugin Package

Common Usage Examples

# Embed a dependency that isn't available as a separate dynamic plugin
plugins/catalog-backend-module-github-org: --embed-package @backstage/plugin-catalog-backend-module-github

# Suppress a native module that causes build issues
plugins/techdocs-backend: --embed-package @backstage/plugin-search-backend-module-techdocs --suppress-native-package cpu-features

# Force a @backstage package to be bundled (not shared)
plugins/notifications-backend: --shared-package '!/@backstage/plugin-notifications/' --embed-package @backstage/plugin-notifications-backend

Workflow Inputs

When triggering exports via GitHub Actions, the following inputs are available.

Workflow: export-workspaces-as-dynamic.yaml

Export Workflow Inputs

Input Type Description
workspace-path string Relative path to a single workspace (e.g., workspaces/backstage)
overlay-branch string Branch of the overlay structure
node-version string Node.js version (defaults to versions.json)
janus-cli-version string CLI package version (defaults to versions.json)
cli-package string CLI package name (defaults to versions.json)
publish-container boolean Whether to publish OCI images
image-repository-prefix string OCI registry prefix
upload-project-on-error boolean Upload workspace on failure for debugging

Triggering via GitHub CLI

# Export all plugins in a workspace
gh workflow run export-workspaces-as-dynamic.yaml \
  -f workspace-path="workspaces/backstage" \
  -f overlay-branch="main" \
  -f publish-container=true

# Export with custom Node version
gh workflow run export-workspaces-as-dynamic.yaml \
  -f workspace-path="workspaces/my-plugin" \
  -f overlay-branch="main" \
  -f node-version="22.19.0" \
  -f publish-container=false

PR Commands

When working with Pull Requests, use these comment commands on the PR (handled by pr-actions.yaml).

Requirements (all commands in this section):

  • The PR must touch exactly one workspace (files under workspaces/<name>/...), or the head branch must match workspaces/release-*__<name> so the workspace can be inferred.
  • Use one slash command per comment (multiple commands in one comment are rejected).
Command Action
/publish Build and publish test OCI artifacts
/smoketest Re-run smoke tests with the default branch-derived RHDH image (requires prior /publish)
/smoketest <tag> Re-run smoke tests with quay.io/rhdh-community/rhdh:<tag> (allowlisted tag formats, requires prior /publish)
/update-versions Copy versions.json from the PR base branch onto the PR branch so it matches the release line
/update-commit Re-run automatic plugin repo ref discovery for that workspace and update the PR branch

Use /update-versions when CI reports that versions.json on your PR does not match the release branch you are targeting. Use /update-commit when you want refreshed upstream refs (for example source.json) from discovery without editing them by hand.

What /publish Does

  1. Checks out the overlay branch
  2. Clones the source repository at the specified repo-ref
  3. Applies any patches from patches/
  4. Installs dependencies
  5. Builds the plugins
  6. Exports as dynamic plugins
  7. Packages as OCI containers
  8. Publishes to ghcr.io with tag pr_<number>__<version>
  9. Posts OCI references as a PR comment

What /update-versions Does

  1. Reads the root versions.json file from the PR base branch (for example release-1.5).
  2. Writes that same content onto your PR head branch so the PR’s versions.json matches the release line.
  3. Runs with force enabled: if your branch had local edits to versions.json, they can be overwrittenβ€”resolve intentional differences elsewhere (for example follow up with a separate commit only if policy allows).

Workflow: update-prs-with-release-branch-commits.yaml.

What /update-commit Does

  1. Resolves the single workspace for the PR (same rules as /publish).
  2. Invokes the update plugins repository references pipeline for that workspace only, scoped to the PR (same automation family as the scheduled discovery workflow, with allow-workspace-addition disabled so new workspaces are not created from the comment path).
  3. Updates discovery-managed inputs on the PR branch (such as source.json repo-ref / discovery outputs for that workspace)β€”not versions.json (use /update-versions for that).

Workflow: update-plugins-repo-refs.yaml.


Overlays vs Patches

Feature Overlay Patch
Scope Single plugin Entire workspace
Method Replace/add files Line-by-line changes
Location plugins/[name]/overlay/ patches/*.patch
Use Case Add new files, replace implementations Fix bugs, modify configs

When to Use Overlays

  • Adding new source files to a plugin
  • Replacing entire modules or implementations
  • Adding configuration files

Example structure:

workspaces/backstage/plugins/api-docs-module-protoc-gen-doc/
└── overlay/
    β”œβ”€β”€ package.json
    └── src/
        └── api.ts

When to Use Patches

  • Fixing build issues
  • Modifying package.json fields
  • Small, targeted source changes

See 06 - Patch Management for details.


Troubleshooting

Build Failures

  1. Check workflow logs – Look for the specific error message

  2. Enable debug upload:

    gh workflow run export-workspaces-as-dynamic.yaml \
      -f workspace-path="workspaces/failing-plugin" \
      -f upload-project-on-error=true
  3. Download the artifact and inspect locally

Integrity Check Failures

Symptom: Workflow logs show an integrity mismatch for a package.

Cause: The export process verifies that the package.json fields in the checked-out source match the metadata declared in the overlay (e.g., package name, version). A mismatch usually means source.json:repo-ref points to a different version than what metadata/*.yaml:spec.version declares.

Solution:

  1. Verify source.json:repo-ref points to the correct tag or commit
  2. Confirm that spec.version and spec.packageName in your metadata files match the source package.json at that ref
  3. If the mismatch is intentional (e.g., a patch changes the version), document the reason in the PR

Missing Dependencies

Symptom: Cannot find module '@backstage/some-package'

Solution: Add --embed-package @backstage/some-package to the plugin entry in plugins-list.yaml

Native Module Errors

Symptom: Build fails with native compilation errors

Solution: Add --suppress-native-package [package-name] if the native module isn't needed at runtime


Next Steps

Clone this wiki locally