Generated banner for Grafana Scenes
Generated logo for Grafana Scenes

Grafana Scenes

Grafana LabsOfficialPublished by Grafana Labs

  • Skill
  • Tool integration
  • Cloud and DevOps
  • Apache-2.0
  • No issues found

From the author

Build Grafana plugin pages using the @grafana/scenes framework. Use when creating new scene pages, adding panels/visualizations, setting up drilldown navigation, defining variables, configuring query runners, building table/timeseries/stat panels, or extending SceneObjectBase for custom scene objects. Triggers on any work involving SceneApp, SceneAppPage, EmbeddedScene, SceneQueryRunner, SceneDataTransformer, PanelBuilders, SceneFlexLayout, QueryVariable, or drilldown/tab configuration in Grafana plugins.
— the description by Grafana Labs

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The @grafana/scenes framework provides a declarative, object-oriented approach to building complex, interactive pages within Grafana plugins. By composing a tree of scene objects—such as SceneApp, SceneAppPage, and EmbeddedScene—developers can manage data, variables, time ranges, and layouts in a hierarchical and reactive manner. This skill covers the implementation of core scene components, including query runners, data transformers, panel builders, and navigation patterns like drilldowns and tabs.

What it does

  • Defines hierarchical scene structures using SceneApp and EmbeddedScene objects.
  • Configures data fetching and transformation with SceneQueryRunner and SceneDataTransformer.
  • Builds standard visualizations like tables, timeseries, and stats using PanelBuilders.
  • Implements dynamic navigation through drilldowns and tabbed sub-pages.
  • Manages state and variables across the scene tree for reactive UI updates.
  • Supports custom interactive UI components by extending SceneObjectBase.

When to use it

  • When developing custom Grafana plugins that require complex, multi-view dashboards.
  • When you need to implement drill-down navigation or tabbed interfaces within a plugin.
  • When building reactive UIs that depend on Grafana variables or time range selections.
  • When you need to apply custom data transformations or RxJS operators to query results.
  • When creating custom interactive widgets that need to integrate with the Grafana scene lifecycle.

Advantages

  • Declarative structure simplifies the management of complex dashboard states.
  • Hierarchical data and variable propagation reduces boilerplate code.
  • Native support for standard Grafana panel types and transformation pipelines.
  • Lazy loading of scenes improves performance for complex plugin pages.
  • Highly extensible architecture allows for custom interactive components.

Usage examples

“How do I create a basic scene page with a table panel in my Grafana plugin?”
You define a SceneQueryRunner for data, use PanelBuilders.table() to create the visualization, and wrap them in an EmbeddedScene with a SceneFlexLayout.
“How can I add drill-down navigation to my scene page?”
You configure the drilldowns property in your SceneAppPage, defining a routePath with a wildcard and a getPage factory function to return the detail view.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/grafana/grafana-scenes/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip grafana-scenes.zip -d .agents/skills

Documentation by Grafana Labs

@grafana/scenes Framework

Build reactive, data-driven Grafana plugin pages with declarative scene objects.

Core Concepts

Scenes composes a tree of objects: SceneApp → SceneAppPage → EmbeddedScene → layouts → panels. Each node can own data ($data), variables ($variables), time ranges ($timeRange), and behaviors ($behaviors) that propagate down the tree.

Quick Start: New Scene Page

1. Create the scene file
// src/components/scenes/MyFeature/scene.tsx
import {
  EmbeddedScene, SceneFlexLayout, SceneFlexItem,
  SceneQueryRunner, SceneVariableSet, QueryVariable,
  PanelBuilders, VariableValueSelectors, SceneControlsSpacer,
} from '@grafana/scenes';

export function getMyFeatureScene(params: { datasource: DataSourceRef }) {
  const queryRunner = new SceneQueryRunner({
    datasource: params.datasource,
    queries: [{ refId: 'A', expr: 'up{cluster=~"$cluster"}', instant: true, format: 'table' }],
  });

  const panel = PanelBuilders.table()
    .setData(queryRunner)
    .setTitle('My Table')
    .build();

  return new EmbeddedScene({
    $variables: new SceneVariableSet({
      variables: [
        new QueryVariable({
          name: 'cluster',
          query: 'label_values(up, cluster)',
          datasource: params.datasource,
          isMulti: true, includeAll: true, defaultToAll: true,
        }),
      ],
    }),
    controls: [new VariableValueSelectors({}), new SceneControlsSpacer()],
    body: new SceneFlexLayout({
      direction: 'column',
      children: [new SceneFlexItem({ body: panel })],
    }),
  });
}
2. Create the page
// src/components/scenes/MyFeature/MyFeature.tsx
import { SceneAppPage, SceneTimeRange } from '@grafana/scenes';

export function getMyFeaturePage(params) {
  return new SceneAppPage({
    title: 'My Feature',
    url: '/a/my-plugin-id/my-feature',
    routePath: 'my-feature/*',
    $timeRange: new SceneTimeRange({ from: 'now-1h', to: 'now' }),
    getScene: () => getMyFeatureScene(params),
    drilldowns: [],
  });
}
3. Register in SceneApp

Add the page to the SceneApp pages array in the root scene file.

Key Patterns

Drilldowns (click-through navigation)
drilldowns: [{
  routePath: ':cluster/*',
  getPage: (match, parent) => new SceneAppPage({
    title: decodeURIComponent(match.params.cluster),
    url: `${parent.state.url}/${match.params.cluster}`,
    routePath: `${match.params.cluster}/*`,
    getScene: () => detailScene(decodeURIComponent(match.params.cluster)),
  }),
}]
Tabs (sub-pages within a detail view)

Pass tabs: [SceneAppPage, ...] instead of getScene on a SceneAppPage. Each tab is itself a SceneAppPage with its own scene.

Query with transformations

Wrap a SceneQueryRunner in SceneDataTransformer to apply Grafana transforms or custom RxJS operators:

new SceneDataTransformer({
  $data: queryRunner,
  transformations: [
    { id: 'organize', options: { renameByName: { 'Value #A': 'CPU' } } },
    (ctx) => (source) => source.pipe(map((frames) => /* custom transform */)),
  ],
})
Custom scene object

Extend SceneObjectBase with a static Component for custom interactive UI:

class MyWidget extends SceneObjectBase<MyWidgetState> {
  static Component = ({ model }: SceneComponentProps<MyWidget>) => {
    const state = model.useState();
    return <div>{state.value}</div>;
  };
}
Table column overrides

Build ConfigOverrideRule objects for drill-down links, filtering, units, widths, custom cells.

Panel types

PanelBuilders.table(), .timeseries(), .stat(), .gauge(), .barchart() — chain .setData(), .setTitle(), .setUnit(), .setOption(), .setOverrides(), then .build().

Common Pitfalls

  • Always use routePath: 'path/*' (with wildcard) on pages that have drilldowns or tabs

  • encodeURIComponent/decodeURIComponent URL params — K8s names can contain /

  • Variables referenced in queries as $varName must exist in an ancestor SceneVariableSet

  • getScene is called lazily; don't create side effects in the factory

  • For instant queries, set both instant: true and format: 'table'

Resources

Files

ATTRIBUTION.md

Attribution

This folder is an unmodified copy of the Agent Skill "grafana-scenes", distributed by AutoGineer (https://autogineer.com/agent-skills).

The skill's own files are unmodified copies. AutoGineer is not affiliated with or endorsed by the author or the publisher.

Files added by AutoGineer

  • ATTRIBUTION.md: this file, written by AutoGineer

  • LICENSE: copied from LICENSE

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs Node.js

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Published by
Grafana Labs
Publisher
Grafana Labs (Official)
Source
grafana/skills · skills/grafana-plugins/grafana-scenes · commit 8fb72a5
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Grafana Labs.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download grafana-scenes.zip