This package provides experimental support for dynamic backend features (plugins and modules) in Backstage, allowing you to load plugins at runtime from a separate directory without including them in your main application's package.json.
This enables:
Important: This service handles loading only - packaging and distribution are separate concerns with multiple approaches available (see Packaging Approaches section).
@backstage/frontend-dynamic-feature-loader: Companion package for loading dynamic frontend plugins. This is only supported in the New Frontend System. For more details, checkout the README.The service consists of several key components:
dynamicPlugins.rootDirectory) for plugin packagesmain, backstage.role)Add the service to your backend application:
yarn add @backstage/backend-dynamic-feature-service
import { createBackend } from '@backstage/backend-defaults';
import { dynamicPluginsFeatureLoader } from '@backstage/backend-dynamic-feature-service';
const backend = createBackend();
// Add this line to enable dynamic plugin support:
backend.add(dynamicPluginsFeatureLoader);
// ... your other plugins
backend.start();
Configure the dynamic plugins directory in your app-config.yaml:
dynamicPlugins:
rootDirectory: dynamic-plugins-root
Before exploring specific packaging approaches, it's important to understand what constitutes a valid dynamic plugin package. Dynamic plugins follow the basic rules of Node.js packages, including:
Package contents:
dist/.config-schema.json) for plugin configuration validationnode_modules folder containing private dependencies for backend pluginsRequired package.json fields:
name: Package identifierversion: Package versionmain: Entry point to the plugin's JavaScript codebackstage.role: Must be set to "backend-plugin" or "backend-plugin-module"Since this service only handles loading, you would choose a packaging approach based on your plugin's dependencies:
When to use: Plugin only uses dependencies that are already provided by the main Backstage application.
How to apply:
cd my-backstage-plugin
yarn pack
# Results in: package.tgz
# Extract to dynamic plugins directory
mkdir -p /path/to/dynamic-plugins-root/my-backstage-plugin
tar -xzf package.tgz -C /path/to/dynamic-plugins-root/my-backstage-plugin --strip-components=1
Why this works: The plugin can resolve all its dependencies from the main application's node_modules.
Reality: Most plugins have private dependencies not available in the main application, so this approach has limited applicability.
When to use: Plugin has private dependencies not available in the main Backstage application.
How to apply:
# Package the plugin
cd my-backstage-plugin
yarn pack
# Extract and install dependencies
mkdir -p /path/to/dynamic-plugins-root/my-backstage-plugin
tar -xzf package.tgz -C /path/to/dynamic-plugin-root/my-backstage-plugin --strip-components=1
cp yarn.lock /path/to/dynamic-plugin-root/my-backstage-plugin
cd /path/to/dynamic-plugins-root/my-backstage-plugin
yarn install # Installs all the plugin's dependencies
Why this works: Each plugin gets its own node_modules directory with all its dependencies.
Example scenario: Plugin needs axios@1.4.0 which isn't available in the main application.
When to use: When you want to produce self-contained dynamic plugin packages that can be directly extracted without any post-action, and systematically use the core @backstage dependencies provided by the Backstage application.
What a packaging CLI needs to do:
@backstage/* packages from dependencies to peerDependencies in package.jsondependencies sectionnode_modules@backstage/* packages but includes its own private dependenciesBenefits:
@backstage/* packages (no version conflicts), enabling the future implementation of @backstage dependency version checking at start timeExample implementation: The @red-hat-developer-hub/cli tool implements this approach:
cd my-backstage-plugin
npx @red-hat-developer-hub/cli@latest plugin export
# Creates a self-contained package with embedded dependencies in the `/dist-dynamic` sub-folder
# Deploy the generated package
cp -r dist-dynamic /path/to/dynamic-plugins-root/my-backstage-plugin