Chapter 8. Front-end plugin wiring


You can configure front-end plugins to customize icons, integrate components at mount points, and offer or replace utility APIs.

8.1. Understanding front-end plugin wiring

You can configure front-end plugins to customize icons, integrate components at mount points, and offer or replace utility APIs.

8.1.1. Front-end plugin wiring

Front-end plugin wiring integrates dynamic front-end plugin components, such as new pages, UI extensions, icons, and APIs, into Red Hat Developer Hub.

Because the dynamic plugins load at runtime, the core application must discover and connect the exported assets of the plugin to the appropriate user interface systems and locations.

Because dynamic front-end plugins load their code at runtime, the Developer Hub application requires explicit instructions to integrate the plugin components in the user interface (UI).

Front-end wiring provides the metadata and instructions necessary to bridge this gap, informing the applications on how to:

The wiring configuration, typically located in app-config.yaml or dynamic-plugins-config.yaml, gives the application the necessary metadata (including the component names, paths, and integration points) to render and use the plugin features.

8.1.1.2. Consequences of skipping front-end wiring

If you skip front-end wiring, the system discovers the plugin but does not load it because front-end plugins require explicit configuration.

You can expect the following behavior when you skip front-end wiring:

Disabled functionality
The Backstage application cannot integrate or use the plugin exports.
Invisible components
New pages, sidebar links, or custom cards do not render in the application UI.
Unregistered APIs
Custom utility APIs or API overrides provided by the plugin are not registered in the application API system, which can cause plugins or components to fail.
Unused assets
Icons, translations, and themes are not registered or available for use.
Tip

If a plugin is not visible even with front-end wiring, the plugin is likely misconfigured. Troubleshoot the issue by checking the Console tab in the Developer Tools of your browser for specific error messages or warnings.

A dynamic front-end plugin requires front-end wiring when it exports a feature for integration into the main Backstage application UI. The following scenarios require wiring:

Expand
ScenarioWiring configurationDescription

Extending entity tabs

entityTabs

Add or customize a tab on the Catalog entity view.

Binding routes

routeBindings

Link a route in one plugin to an external route defined by another plugin.

Integrating custom APIs

apiFactories

Supply a custom utility API implementation or override an existing one.

Enabling new pages/Routes

dynamicRoutes

Add a new page and route to the application (for example, /my-plugin).

Extending existing pages/UI

mountPoints

Inject custom widgets, cards, listeners, or providers into existing pages (for example, the Catalog entity page).

Customizing sidebar navigation

dynamicRoutes.menuItem, menuItems

Add a new entry to the main sidebar or customize its order and nesting.

Adding icons/Theming

appIcons, themes

Add custom icons to the application catalog or define a new Backstage theme.

Scaffolder/TechDocs extensions

scaffolderFieldExtensions, techdocsAddons

Expose custom field extensions for the Scaffolder or new add-ons for TechDocs.

Translation resources

translationResources

Offer new translation files or override default plugin translations.

8.1.1.3.1. Example of Front-end wiring workflow

Front-end wiring configuration occurs in the app-config.yaml or a dedicated dynamic-plugins-config.yaml file. The dynamic plugin exposes components, routes, or APIs. For example, a module exports a plugin component.

The application administrator defines the wiring in the configuration file, using the plugin package name to register the exports, such as adding a new page with a sidebar link.

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-plugin-package-name: # The plugin's unique package name
            dynamicRoutes: # Wiring for a new page/route
              - path: /my-new-page # The desired URL path
                importName: <my-plugin>PluginPage # The exported component name
                menuItem: # Wiring for the sidebar entry
                  icon: favorite # A registered icon name
                  text: My Custom Page

When the application loads, it performs the following steps:

  1. It parses the dynamic-plugins-config.yaml.
  2. It uses the <plugin_path_or_url> to download the plugin bundle using the dynamic loading mechanism.
  3. If the package exports the plugin object, the application adds it to the list provided to the Backstage createApp API, registering the plugin properly with the front-end application.
  4. It uses the configuration block (dynamicRoutes, menuItem) to:

    • Add an entry to the internal router mapping /my-new-page to the <my-plugin>PluginPage component.
    • Construct and render a new sidebar item labeled My Custom Page, pointing to the /my-new-page route.
Note

If the configuration is missing, steps 1 and 2 might still occur, but the application skips the final registration in step 3 and the wiring/rendering in step 4, and no UI changes occur.

8.2. Extend internal icon catalog

You can use the internal catalog to fetch icons for configured routes with sidebar navigation menu entry.

Procedure

  • Add a custom icon to the internal icon catalog for use in the menu item of a plugin by using the appIcons configuration as shown in the following example:

    # dynamic-plugins-config.yaml
    plugins:
      - plugin: <plugin_path_or_url>
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              my-plugin:  # The plugin package name
                appIcons:
                  - name: <catalogName> # The icon catalog name
                    # (Optional): The set of assets to access within the plugin. If not specified, the system uses the PluginRoot module.
                    module: CustomModule
                    # (Optional): The actual component name to be rendered as a standalone page. If not specified, the system uses the default export.
                    importName: <CustomIcon>
    Note

    The package_name key under dynamicPlugins.frontend must match the scalprum.name value in your plugin’s package.json. This ensures your dynamic plugin loads correctly during runtime.

8.3. Define dynamic routes for new plugin pages

Use this procedure to configure dynamic routes for new plugin pages in the application.

Procedure

  1. Define each route by specifying a unique path and, if needed, an importName if it is different from the default export.
  2. Expose additional routes in a dynamic plugin by configuring dynamicRoutes as shown in the following example:

    # dynamic-plugins-config.yaml
    plugins:
      - plugin: <plugin_path_or_url>
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              my-plugin: # The plugin package name
                dynamicRoutes:
                    # The unique path in the application. The path cannot override existing routes except the / home route.
                  - path: /my-plugin
                    # (Optional): The set of assets to access within the plugin. If not specified, the system uses the PluginRoot module.
                    module: CustomModule
                    # (Optional): The component name as a standalone page. If not specified, the system uses the default export.
                    importName: <my_plugin>PluginPage
                    # Allows you to extend the main sidebar navigation and point to a new route.
                    menuItem:
                      icon: # home | group | category | extension | school | <my_icon>
                      text: <my-plugin label>
                      enabled: false
                    config: # (Optional): Passes props to a custom sidebar item
                      props: ...

    The menuItem accepts the following properties:

  3. text: The label shown to the user.
  4. icon: The Backstage system icon name.
  5. enabled: Optional: When you set this to false, you can remove a menuItem from the sidebar.
  6. importName: Specifies the optional name of an exported SidebarItem component.

    To configure a custom SidebarItem to enhance experiences such as notification badges, ensure the component accepts the following properties:

    export type MySidebarItemProps = {
      to: string; // supplied by the sidebar during rendering, this will be the path configured for the dynamicRoute
    };
    # dynamic-plugins-config.yaml
    plugins:
      - plugin: <plugin_path_or_url>
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              my-dynamic-plugin-package-name:
                dynamicRoutes:
                  - importName: CustomPage
                    menuItem:
                      config:
                        props:
                          text: Click Me!
                      importName: SimpleSidebarItem
                    path: /custom_page

You can customize the order and parent-child relationships of plugin menu items in the main sidebar navigation by using the menu items configuration as shown in the following example:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-plugin:
            menuItems:
              <menu_item_name>:
                icon: <icon_name>Icon
                title: <plugin_name> Plugin Page
                priority: 10
                parent: favorites
                enabled: false

where:

my-plugin
The plugin package name.
<menu_item_name>
The unique name in the main sidebar navigation, for example, either a standalone menu item or a parent menu item.
icon
Optional: The icon for the menu item, which refers to a Backstage system icon.
title
Optional: The display title of the menu item.
priority
Optional: The order in which menu items appear. The default priority is 0.
parent
Optional: Defines the parent menu item to nest the current item under.
enabled
Optional: When you set this to false, you can remove a menuItem from the sidebar.

Handling Complex Paths:

  • For simple paths such as path: /my-plugin, the menu_item_name should be my-plugin.
  • For complex paths such as /metrics/users/info, the menu_item_name should represent the full path in dot notation (for example metrics.users.info).
  • Ignore trailing and leading slashes in paths as follows:

    • For path: /docs, the menu_item_name is docs.
    • For path: /metrics/users, the menu_item_name is metrics.users.
Note

Red Hat Developer Hub supports up to 3 levels of nested menu items.

8.5. Binding to existing plugins

You can bind to existing plugins and their routes, and declare new targets sourced from dynamic plugins as shown in the following routeBindings configuration:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-plugin:
            routeBindings:
              targets:
                - name: <plugin_name>Plugin
                  importName: <plugin_key>Plugin
                  module: CustomModule
              bindings:
                - bindTarget: "<plugin_name>Plugin.externalRoutes"
                  bindMap:
                    headerLink: "<plugin_name>Plugin.routes.root"

where:

my-plugin
The plugin package name.
targets
A new bind target.
name
Optional: Defaults to importName. Explicit name of the plugin that exposes the bind target.
importName
Required: Explicit import name that references a BackstagePlugin<{}> implementation.
module
Optional: Same as the key in scalprum.exposedModules in the package.json file of the plugin.
bindTarget
Required: One of the supported or imported bind targets.
bindMap
Required: A map of route bindings similar to bind function options.

To configure routeBindings, complete the following steps:

  1. Define new targets using routeBindings.targets. Set the required importName to a BackstagePlugin<{}> implementation.
  2. Declare route bindings using the routeBindings.bindings field by setting bindTarget to the name of the target to bind to. This is a dynamic or static target, such as:

    • catalogPlugin.externalRoutes
    • catalogImportPlugin.externalRoutes
    • techdocsPlugin.externalRoutes
    • scaffolderPlugin.externalRoutes

      You can extend existing pages with additional content by using mount points. The application defines these identifiers throughout the system.

8.6. Using mount points

Mount points let you attach UI components to predefined locations in the Red Hat Developer Hub interface, such as entity pages, application headers, listeners, and providers.

8.6.1. Using mount points

Red Hat Developer Hub defines mount points as identifiers available across the application. You can use these points to extend existing pages with additional content.

8.6.1.1. Customizing entity page

You can extend catalog components and additional views.

The available mount points include the following:

Expand
Mount pointDescriptionVisible even when you enable no plugins

admin.page.plugins

Administration plugins page

NO

admin.page.rbac

Administration RBAC page

NO

entity.context.menu

Catalog entity menu

YES for all entities

entity.page.overview

Catalog entity overview page

YES for all entities

entity.page.topology

Catalog entity Topology tab

NO

entity.page.issues

Catalog entity Issues tab

NO

entity.page.pull-requests

Catalog entity Pull Requests tab

NO

entity.page.ci

Catalog entity CI tab

NO

entity.page.cd

Catalog entity CD tab

NO

entity.page.kubernetes

Catalog entity Kubernetes tab

NO

entity.page.image-registry

Catalog entity Image Registry tab

NO

entity.page.monitoring

Catalog entity Monitoring tab

NO

entity.page.lighthouse

Catalog entity Lighthouse tab

NO

entity.page.api

Catalog entity API tab

YES for entity of kind: Component and spec.type: 'service'

entity.page.dependencies

Catalog entity Dependencies tab

YES for entity of kind: Component

entity.page.docs

Catalog entity Documentation tab

YES for entity that satisfies isTechDocsAvailable

entity.page.definition

Catalog entity Definitions tab

YES for entity of kind: Api

entity.page.diagram

Catalog entity Diagram tab

YES for entity of kind: System

search.page.types

Search result type

YES, default catalog search type is available

search.page.filters

Search filters

YES, default catalog kind and lifecycle filters are visible

search.page.results

Search results content

YES, default catalog search is present

Note

Mount points within a catalog such as entity.page. render as tabs and become visible only if at least one plugin contributes to them, or if they can render static content.

Each entity.page. mount point has the following variations:

  • /context type that serves to create React contexts
  • /cards type for regular React components

The following is an example of the overall configuration structure of a mount point:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-plugin: # The plugin package name
            mountPoints: # (Optional): Uses existing mount points
              - mountPoint: <mountPointName>/[cards|context]
                module: CustomModule
                importName: <pluginName>PluginPage
                config: # (Optional): Allows you to pass additional configuration to the component
                  layout: {} # Used only in /cards type which renders visible content
                  # Use only in /cards type which renders visible content. if is passed to <EntitySwitch.Case if={<here>}.
                  if:
                    allOf|anyOf|oneOf:
                      - isMyPluginAvailable
                      - isKind: component
                      - isType: service
                      - hasAnnotation: annotationKey
                  props: {} # Useful when you are passing additional data to the component

The available conditions include:

  • allOf: The configuration must meet all conditions
  • anyOf: The configuration must meet at least one condition
  • oneOf: The configuration must meet only one condition

Conditions are:

  • isKind: Accepts a string or a list of string with entity kinds. For example isKind: component renders the component only for entity of kind: Component.
  • isType: Accepts a string or a list of string with entity types. For example isType: service renders the component only for entities of spec.type: 'service'.
  • hasAnnotation: Accepts a string or a list of string with annotation keys. For example hasAnnotation: my-annotation renders the component only for entities that have defined metadata.annotations['my-annotation'].
  • Condition imported from the module of the plugin: Must be function name exported from the same module within the plugin. For example isMyPluginAvailable renders the component only if isMyPluginAvailable function returns true. The function must have the following signature: (e: Entity) ⇒ boolean.

The entity page supports adding more items to the menu at the top right of the page. The exported component is a form of dialog wrapper component that accepts an open boolean property and an onClose event handler property as shown in the following example:

export type SimpleDialogProps = {
  open: boolean;
  onClose: () => void;
};

You can configure the menu entry by using the props configuration entry for the mount point. The title and icon properties sets the text and icon of the menu item. You can use any system icon or icon added through a dynamic plugin. The following is an example configuration:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-dynamic-plugin-package:
            appIcons:
              - name: dialogIcon
                importName: DialogIcon
            mountPoints:
              - mountPoint: entity.context.menu
                importName: SimpleDialog
                config:
                  props:
                    title: Open Simple Dialog
                    icon: dialogIcon

8.6.1.2. Adding application header

You can customize global headers by specifying configurations in the app-config.yaml file as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-plugin:  # The plugin package name
      mountPoints:
        - mountPoint: application/header # Adds the header as a global header
          importName: <header_component> # Specifies the component exported by the global header plugin
          config:
            position: above-main-content # Supported values: (`above-main-content`| above-sidebar`)
Note

To configure many global headers at different positions, add entries to the mountPoints field.

8.6.1.3. Adding application listeners

You can add application listeners by using the application/listener mount point as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      mountPoints:
        - mountPoint: application/listener
          importName: <exported listener component>
Note

You can configure many application listeners by adding entries to the mountPoints field.

8.6.1.4. Adding application providers

You can add application providers by using the application/provider mount point. You can use a mount point to configure a context provider as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      dynamicRoutes:
        - path: /<route>
          importName: Component # The component to load on the route
      mountPoints:
        - mountPoint: application/provider
          importName: <exported provider component>
Note
  1. You can configure many application providers by adding entries to the mountPoints field.
  2. The package_name key under dynamicPlugins.frontend must match the scalprum.name value in the package.json file of your plugin. This ensures your dynamic plugin loads correctly at runtime.

8.7. Customizing and extending entity tabs

You can customize and extend the set of tabs by using the entityTabs configuration as follows:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-plugin: # The plugin package name
            entityTabs:
              # Specify a new tab
              - path: /new-path
                title: My New Tab
                mountPoint: entity.page.my-new-tab
              # Change an existing tab's title or mount point
              - path: /
                title: General
                mountPoint: entity.page.overview
                # Specify the sub-path route in the catalog where this tab is available
              - path: "/pr"
                title: "Changed Pull/Merge Requests" # Specify the title you want to display
                priority: 1
                # The base mount point name available on the tab. This name expands to create two mount points per tab, with` /context` and with `/cards`
                mountPoint: "entity.page.pull-requests"
              - path: "/"
                title: "Changed Overview"
                mountPoint: "entity.page.overview"
                # Specify the order of tabs. The tabs with higher priority values appear first
                priority: -6

You can configure dynamic front-end plugins to target the mount points exposed by the entityTabs configuration. The following are the default catalog entity routes in the default order:

Expand
RouteTitleMount PointEntity Kind

/

Overview

entity.page.overview

Any

/topology

Topology

entity.page.topology

Any

/issues

Issues

entity.page.issues

Any

/pr

CPull/Merge Requests

entity.page.pull-requests

Any

/ci

CI

entity.page.ci`

VAny

/cd

CD

entity.page.cd

Any

/kubernetes

Kubernetes

entity.page.kubernetes

Any

/image-registry

Image Registry

entity.page.image-registry

Any

/monitoring

Monitoring

entity.page.monitoring

Any

/lighthouse

Lighthouse

entity.page.lighthouse

Any

/api

Api

entity.page.api

kind: Service or kind: Component

/dependencies

Dependencies

entity.page.dependencies

kind: Component

/docs

Docs

entity.page.docs

Any

/definition

Definition

entity.page.definition

kind: API

/system

Diagram

entity.page.diagram

kind: System

Note

Mount points within Catalog such as `entity.page.*` render as tabs and become visible only if at least one plugin contributes to them, or if they can render static content.

8.8. Using a custom SignInPage component

In Red Hat Developer Hub (RHDH), the SignInPage component manages authentication flow. By default, Developer Hub uses a static SignInPage.

When you configure a custom SignInPage:

  • The system loads the specified importName component from your dynamic plugin.
  • The component returns a configured SignInPage that connects the required authentication provider factories.
  • You specify only one signInPage for the application at a time.
dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      signInPage:
        importName: CustomSignInPage
Note

The package_name specified under dynamicPlugins.frontend must match the scalprum.name value in the package.json file of your plugin to ensure the dynamic plugin loads correctly at runtime.

The module field is optional and specifies the set of assets that you must access within the dynamic plugin. By default, the system uses the PluginRoot module.

8.9. Providing custom Scaffolder field extensions

With the Scaffolder component in Red Hat Developer Hub (RHDH), you can create software components by using templates through a guided wizard. You can extend the functionality of the Scaffolder by adding custom form fields as dynamic plugins by using the scaffolderFieldExtensions configuration.

With custom field extensions, you can add specialized form fields that capture domain-specific data during the scaffolding process, such as environment selectors, input validations, or repository checks.

When you configure custom Scaffolder field extensions:

  • The dynamic plugin exposes the field extension component using createScaffolderFieldExtension.
  • Each field extension requires a unique importName for registration.
  • You register many field extensions by listing each in the configuration.
dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      scaffolderFieldExtensions:
        - importName: MyNewFieldExtension # References the exported Scaffolder field extension component from your plugin
Note

The module field is optional and specifies which set of assets to access within the plugin. By default, the system uses the PluginRoot module, consistent with the scalprum.exposedModules key in the package.json file of your package.

8.10. Providing additional utility APIs

If a dynamic plugin exports the plugin object returned by createPlugin, the createApp API receives it. All API factories exported by the plugin are automatically registered and available in the front-end application.

You can add an entry to the dynamicPlugins.frontend configuration when a dynamic plugin has only API factories as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-dynamic-plugin-package-with-api-factories: {}

However, when the dynamic plugin is not exporting the plugin object, you must explicitly configure each API factory. Use the apiFactories configuration to register them with the createApp API as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      apiFactories:
        # (Optional): Specify the import name that references a `AnyApiFactory<{}>` implementation. (Defaults to `default` export)
        - importName: BarApi
          # (Optional): An argument which specifies the assets you want to access within the plugin. If not provided, the default module named `PluginRoot` is used
          module: CustomModule

An API factory from a dynamic plugin overrides the API factories that the Developer Hub application initializes when both specify the same API ref ID. A dynamic plugin can export AnyApiFactory<{}> to cater for some specific use case as shown in the following example:

export const customScmAuthApiFactory = createApiFactory({
  api: scmAuthApiRef,
  deps: { githubAuthApi: githubAuthApiRef },
  factory: ({ githubAuthApi }) =>
    ScmAuth.merge(
      ScmAuth.forGithub(githubAuthApi, { host: "github.someinstance.com" }),
      ScmAuth.forGithub(githubAuthApi, {
        host: "github.someotherinstance.com",
      }),
    ),
});

The corresponding configuration that overrides the default ScmAuth API factory that Developer Hub defaults to is as shown in the following example:

dynamicPlugins:
  frontend:
    my-plugin:  # The plugin package name
      apiFactories:
        - importName: customScmAuthApiFactory

You can install new authentication providers from a dynamic plugin that either adds additional configuration support for an existing provider or adds a new authentication provider. The user settings section lists these providers under the Authentication Providers tab.

You can use the providerSettings configuration to add entries for an authentication provider from a dynamic plugin, as shown in the following example:

dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      providerSettings:
        # The title for the authentication provider shown above the user's profile image if available
        - title: My Custom Auth Provider
          # The description of the authentication provider
          description: Sign in using My Custom Auth Provider
          # The ID of the authentication provider as provided to the `createApiRef` API call.
          provider: core.auth.my-custom-auth-provider
Note

provider looks up the corresponding API factory for the authentication provider to connect the provider’s Sign In/Sign Out button.

8.12. Providing custom TechDocs add-ons

If a plugin provides many add-ons, each techdocsAddon entry specifies a unique importName corresponding to the add-on. Front-end plugins expose the TechDocs add-on component by using the techdocsAddons configuration as shown in the following example:

dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      techdocsAddons:
        - importName: ExampleAddon # The exported add-on component
          config:
            props: ... # (Optional): React props to pass to the add-on

8.13. Customizing Red Hat Developer Hub theme

You can customize Developer Hub themes from a dynamic plugin with various configurations as shown in the following example:

import { lightTheme } from './lightTheme';
import { darkTheme } from './darkTheme';
import { UnifiedThemeProvider } from '@backstage/theme';
export const lightThemeProvider = ({ children }: { children: ReactNode }) => (
  <UnifiedThemeProvider theme={lightTheme} children={children} />
);
export const darkThemeProvider = ({ children }: { children: ReactNode }) => (
  <UnifiedThemeProvider theme={darkTheme} children={children} />
);

For more information about creating a custom theme, see creating a custom theme.

You can declare the theme by using the themes configuration as shown in the following example:

dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      themes:
          #  are `light` or `dark`. Using 'light' overrides the app-provided light theme
        - id: light
          title: Light
          variant: light
          icon: someIconReference
          importName: lightThemeProvider
          # The theme name displayed to the user on the *Settings* page. Using 'dark' overrides the app-provided dark theme
        - id: dark
          title: Dark
          variant: dark
          icon: someIconReference # A string reference to a system or app icon
          # The name of the exported theme provider function, the function signature should match `({ children }: { children: ReactNode }): React.JSX.Element`
          importName: darkThemeProvider
Red Hat logoGithubredditYoutubeTwitter

Learn

Try, buy, & sell

Communities

About Red Hat Documentation

We help Red Hat users innovate and achieve their goals with our products and services with content they can trust. Explore our recent updates.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.

About Red Hat

We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

Theme

© 2026 Red Hat
Back to top