Skip to main content

Migrate plugins from Grafana version 11.6.x to 12.0.x

This guide helps you migrate plugins from Grafana version 11.6.x to 12.0.x.

Prerequisites​

Before starting the migration:

  • Back up your plugin code
  • Ensure your development environment is up to date
  • Familiarize yourself with the reactive APIs introduced in Grafana 11.4

Deprecated UI extension APIs removal​

The deprecated UI extension APIs have been removed in Grafana 12 in favor of the new reactive APIs introduced in Grafana 11.4. The following APIs have been removed:

  • usePluginExtensions()
  • usePluginLinkExtensions()
  • usePluginComponentExtensions()
  • getPluginExtensions()
  • getPluginLinkExtensions()
  • getPluginComponentExtensions()
  • AppPlugin.configureExtensionLink()
  • AppPlugin.configureExtensionComponent()

Using any of these APIs in Grafana 12 will result in an error. Additionally, the TypeScript types PluginExtensionLinkConfig and PluginExtensionComponentConfig have been removed.

info

If you need your plugin to work with both Grafana 12.0.x and older versions, you can implement runtime checks to conditionally use the appropriate APIs. For more information, refer to Manage backwards compatibility with runtime checks.

Replace the configureExtensionLink method with the addLink method. Update the extensionPointId parameter to targets, which accepts either a string or string[].

- new AppPlugin().configureExtensionLink({
+ new AppPlugin().addLink({
- extensionPointId: PluginExtensionPoints.DashboardPanelMenu,
+ targets: PluginExtensionPoints.DashboardPanelMenu,
title: 'Component title 0',
description: 'Component description 0',
component: () => <div />,
});

AppPlugin.configureExtensionComponent()​

Replace the configureExtensionComponent method with the addComponent method. Update the extensionPointId parameter to targets, which accepts either a string or string[].

- new AppPlugin().configureExtensionComponent({
+ new AppPlugin().addComponent({
- extensionPointId: PluginExtensionPoints.CommandPalette,
+ targets: PluginExtensionPoints.CommandPalette,
title: 'Component title 0',
description: 'Component description 0',
component: () => <div />,
});

getPluginLinkExtensions() and usePluginLinkExtensions()​

Both the getPluginLinkExtensions() function and the usePluginLinkExtensions() React hook can be replaced with the usePluginLinks() React hook.

getPluginLinkExtensions
- const { extensions } = getPluginLinkExtensions({
+ const { links, isLoading } = usePluginLinks({
extensionPointId: 'grafana/dashboard/panel/menu/v1',
limitPerPlugin: 2,
context: {
panelId: '...',
},
});
usePluginLinkExtensions
- const { extensions, isLoading } = usePluginLinkExtensions({
+ const { links, isLoading } = usePluginLinks({
extensionPointId: 'grafana/dashboard/panel/menu/v1',
limitPerPlugin: 2,
context: {
panelId: '...',
},
});

getPluginComponentExtensions() and usePluginComponentExtensions()​

You can replace both the getPluginComponentExtensions() function and the usePluginComponentExtensions() React hook with the usePluginComponents() React hook.

getPluginComponentExtensions
- const { extensions } = getPluginComponentExtensions({
+ const { components, isLoading } = usePluginComponents({
extensionPointId: 'grafana/user/profile/tab/v1',
limitPerPlugin: 2,
});
usePluginComponentExtensions
- const { extensions, isLoading } = usePluginComponentExtensions({
+ const { components, isLoading } = usePluginComponents({
extensionPointId: 'grafana/user/profile/tab/v1',
limitPerPlugin: 2,
});

getPluginExtensions() and usePluginExtensions()​

Replace the getPluginExtensions() function and the usePluginExtensions() React hook based on their usage:

  • For links: Follow the link extensions instructions.

  • For components: Follow the component extensions instructions.

  • For both links and components: Use both usePluginLinks and usePluginComponents.

PluginExtensionLinkConfig and PluginExtensionComponentConfig​

The types PluginExtensionLinkConfig and PluginExtensionComponentConfig have been removed from @grafana/data. Replace them with PluginExtensionAddedLinkConfig and PluginExtensionAddedComponentConfig, respectively.

GetPluginExtensionsOptions​

The GetPluginExtensionsOptions type has been removed from @grafana/runtime in favor of specific types that match their corresponding hook parameters.

Quick reference​

The following table summarizes the API changes with notes explaining the key differences:

Deprecated APIEquivalent APINotes
AppPlugin.configureExtensionLink()AppPlugin.addLink()extensionPointId parameter renamed to targets, accepts string or string[]
AppPlugin.configureExtensionComponent()AppPlugin.addComponent()extensionPointId parameter renamed to targets, accepts string or string[]
getPluginLinkExtensions()usePluginLinks()Returns { links, isLoading } instead of { extensions }
usePluginLinkExtensions()usePluginLinks()Returns { links, isLoading } instead of { extensions }
getPluginComponentExtensions()usePluginComponents()Returns { components, isLoading } instead of { extensions }
usePluginComponentExtensions()usePluginComponents()Returns { components, isLoading } instead of { extensions, isLoading }
getPluginExtensions()usePluginLinks() or usePluginComponents()Split into two separate hooks based on extension type (links or components)
usePluginExtensions()usePluginLinks() or usePluginComponents()Split into two separate hooks based on extension type (links or components)
PluginExtensionComponentConfigPluginExtensionAddedComponentConfigUpdated type definition for component configuration
PluginExtensionLinkConfigPluginExtensionAddedLinkConfigUpdated type definition for link configuration
GetPluginExtensionsOptionsUsePluginLinksOptions or UsePluginComponentsOptions or UsePluginFunctionsOptionsUpdated type definition for hook parameters

Migrate from Select to Combobox​

Grafana 11.5.0 introduced the new Combobox component as a replacement for the Select component. The Combobox component has been designed with performance in mind, particularly for handling extremely large data sets. See the component documentation for detailed usage guidelines.

The Select and MultiSelect components are now deprecated in Grafana 12 and will not receive substantial updates or fixes. We recommend migrating to Combobox and MultiCombobox.

Basic usage​

For simple use cases, the Combobox component has a similar API to Select.

/**
* Previous Select implementation
*/
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';

const options: SelectableValue[] = [
{ label: 'Loki', value: 'datasource-loki' },
{ label: 'Prometheus', value: 'datasource-prom' },
];
const [value, setValue] = useState<SelectableValue>();

<Select value={value} options={options} onChange={(newOption) => setValue(newOption)} />;

/**
* New Combobox implementation
*/
import { Combobox, ComboboxOption } from '@grafana/ui';

const options: ComboboxOption[] = [
{ label: 'Loki', value: 'datasource-loki' },
{ label: 'Prometheus', value: 'datasource-prom' },
];

// It is preferred to pass in only the 'value' property from options to the value prop
const [value, setValue] = useState<string>();

<Combobox value={value} options={options} onChange={(newOption) => setValue(newOption.value)} />;

Async data loading​

The Combobox component handles asynchronous data loading through a function passed to the options prop. This function:

  • Receives the current input value as a parameter
  • Returns a Promise resolving to ComboboxOption[]
  • Automatically debounces calls to prevent excessive API requests
import { Combobox, ComboboxOption } from '@grafana/ui';

const [value, setValue] = useState<string>();

const loadOptions = useCallback(async (input: string): Promise<ComboboxOption[]> => {
const response = await fetch(`/api/options?query=${input}`);
return response.json();
}, []);

<Combobox value={value} options={loadOptions} onChange={(newOption) => setValue(newOption.value)} />;
warning

Do not request all options on the initial open. It's recommended to use this async behaviour only when calling an API that is able to filter results on the server side.

Quick reference​

The following table summarizes the component deprecations changes with notes explaining the key differences:

DeprecatedEquivalentNotes
SelectComboboxSee props table below
MultiSelectMultiComboboxSee props table below
AsyncSelectComboboxUse an async function for the options prop
VirtualizedSelectComboboxCombobox is virtualised by default
AsyncVirtualizedSelectComboboxCombobox is virtualised by default
AsyncMultiSelectMultiSelectUse an async function for the options prop

The following table summarizes the prop changes with notes explaining the key differences:

DeprecatedEquivalentNotes
SelectableValueComboboxOptionIs exported from @grafana/ui instead
SelectableValue["value"]ComboboxOption["value"]Value is required and must be primitive string | number
SelectableValue["description"]ComboboxOption["description"]Description is no longer wrapped and may be truncated
onChangeonChangeRecommended to only store the value in state
valuevalueRecommended to only pass in the primitive string | number value
optionsoptionsCan be a ComboboxOption[] or a function that returns a Promise<ComboboxOption[]>
isLoadingloadingNot required if using async options
allowCustomValuecreateCustomValueWill emit an object like { label: "Foo", value: "Foo" } from onChange
width="auto"width="auto"minWidth is required when using the auto-sizing input

Many props from the old Select component that controlled subtle behavior or customized rendering - such as createOptionPosition or openMenuOnFocus - are no longer supported, in order to simplify the API and provide a more consistent experience. If you have a specific use case that requires this, please open an issue in the Grafana repo.