Skip to main content
Version: Next

Contribution Types

To facilitate the development of extensions, we define a set of well-defined contribution types that extensions can implement. These contribution types serve as the building blocks for extensions, allowing them to interact with the host application and provide new functionality.

Frontend​

Frontend contribution types allow extensions to extend Superset's user interface with new views, commands, and menu items. Frontend contributions are registered directly in code from your extension's index.tsx entry point.

Views​

Extensions can add new views or panels to the host application, such as custom SQL Lab panels, dashboards, or other UI components. Contribution areas are uniquely identified (e.g., sqllab.panels for SQL Lab panels), enabling seamless integration into specific parts of the application.

import { views } from '@apache-superset/core';
import MyPanel from './MyPanel';

views.registerView(
{ id: 'my-extension.main', name: 'My Panel Name' },
'sqllab.panels',
MyPanel,
);

Commands​

Extensions can define custom commands that can be executed within the host application, such as context-aware actions or menu options. Each command specifies a unique identifier, a title, an optional icon, and a description. Commands can be invoked by users through menus, keyboard shortcuts, or other UI elements.

import { commands } from '@apache-superset/core';

commands.registerCommand(
{
id: 'my-extension.copy-query',
title: 'Copy Query',
icon: 'CopyOutlined',
description: 'Copy the current query to clipboard',
},
() => {
// Command implementation
},
);

Extensions can contribute new menu items or context menus to the host application, providing users with additional actions and options. Each menu item specifies the view and command to execute, the target area, and the location (primary, secondary, or context). Menu contribution areas are uniquely identified (e.g., sqllab.editor for the SQL Lab editor).

import { menus } from '@apache-superset/core';

menus.registerMenuItem(
{ view: 'sqllab.editor', command: 'my-extension.copy-query' },
'sqllab.editor',
'primary',
);

menus.registerMenuItem(
{ view: 'sqllab.editor', command: 'my-extension.prettify' },
'sqllab.editor',
'secondary',
);

menus.registerMenuItem(
{ view: 'sqllab.editor', command: 'my-extension.clear' },
'sqllab.editor',
'context',
);

Editors​

Extensions can replace Superset's default text editors with custom implementations. This enables enhanced editing experiences using alternative editor frameworks like Monaco, CodeMirror, or custom solutions. When an extension registers an editor for a language, it replaces the default editor in all locations that use that language (SQL Lab, Dashboard Properties, CSS editors, etc.).

import { editors } from '@apache-superset/core';
import MonacoSQLEditor from './MonacoSQLEditor';

editors.registerEditor(
{
id: 'my-extension.monaco-sql',
name: 'Monaco SQL Editor',
languages: ['sql'],
},
MonacoSQLEditor,
);

See Editors Extension Point for implementation details.

Chat​

Extensions can add a chat interface to Superset by registering a trigger component and a panel component. The host owns the layout, open/close state, and display mode — the extension only provides the UI. The panel can be displayed as a floating overlay or docked as a resizable sidebar beside the page content, and the user's preference is persisted across reloads.

import { chat } from '@apache-superset/core';
import ChatTrigger from './ChatTrigger';
import ChatPanel from './ChatPanel';

chat.registerChat(
{ id: 'my-org.my-chat', name: 'My Chat' },
ChatTrigger,
ChatPanel,
);

See Chat for implementation details.

Backend​

Backend contribution types allow extensions to extend Superset's server-side capabilities. Backend contributions are registered at startup via classes and functions imported from the auto-discovered entrypoint.py file.

REST API Endpoints​

Extensions can register custom REST API endpoints under the /extensions/ namespace. This dedicated namespace prevents conflicts with built-in endpoints and provides a clear separation between core and extension functionality.

from flask import Response
from flask_appbuilder.api import expose, permission_name, protect, safe
from superset_core.rest_api.api import RestApi
from superset_core.rest_api.decorators import api

@api(
id="my_extension_api",
name="My Extension API",
description="Custom API endpoints for my extension",
)
class MyExtensionAPI(RestApi):
openapi_spec_tag = "My Extension"
class_permission_name = "my_extension_api"

@expose("/hello", methods=("GET",))
@protect()
@safe
@permission_name("read")
def hello(self) -> Response:
return self.response(200, result={"message": "Hello from extension!"})

# Import the class in entrypoint.py to register it
from .api import MyExtensionAPI

Note: The @api decorator automatically detects context and generates appropriate paths:

  • Extension context: /extensions/{publisher}/{name}/ with ID prefixed as extensions.{publisher}.{name}.{id}
  • Host context: /api/v1/ with original ID

For an extension with publisher my-org and name dataset-tools, the endpoint above would be accessible at:

/extensions/my-org/dataset-tools/hello

You can also specify a resource_name parameter to add an additional path segment:

@api(
id="analytics_api",
name="Analytics API",
resource_name="analytics", # Adds /analytics to the path
)
class AnalyticsAPI(RestApi):

@expose("/insights", methods=("GET",))
@protect()
@safe
@permission_name("read")
def insights(self) -> Response:
# This endpoint will be available at:
# /extensions/my-org/dataset-tools/analytics/insights
return self.response(200, result={"insights": []})

MCP Tools​

Extensions can register Python functions as MCP tools that AI agents can discover and call. Tools provide executable functionality such as data processing, custom analytics, or integration with external services. Each tool specifies a unique name and an optional description that helps AI agents decide when to use it.

from superset_core.mcp.decorators import tool

@tool(
name="my-extension.get_summary",
description="Get a summary of recent query activity",
tags=["analytics", "queries"],
)
def get_summary() -> dict:
"""Returns a summary of recent query activity."""
return {"status": "success", "result": {"queries_today": 42}}

See MCP Integration for implementation details.

MCP Prompts​

Extensions can register MCP prompts that provide interactive guidance and context to AI agents. Prompts help agents understand domain-specific workflows, best practices, or troubleshooting steps for your extension's use cases.

from superset_core.mcp.decorators import prompt
from fastmcp import Context

@prompt(
"my-extension.analysis_guide",
title="Analysis Guide",
description="Step-by-step guidance for data analysis workflows",
)
async def analysis_guide(ctx: Context) -> str:
"""Provides guidance for data analysis workflows."""
return """
# Data Analysis Guide

Follow these steps for effective analysis:

1. **Explore your data** - Review available datasets and schema
2. **Build your query** - Use SQL Lab to craft and test queries
3. **Visualize results** - Choose the right chart type for your data

What would you like to analyze today?
"""

See MCP Integration for implementation details.

Semantic Layers​

Extensions can register custom semantic layer implementations that allow Superset to connect to external data modeling frameworks. Each semantic layer defines how to authenticate, discover semantic views (tables/metrics/dimensions), and execute queries against the external system.

from superset_core.semantic_layers.decorators import semantic_layer
from superset_core.semantic_layers.layer import SemanticLayer

from my_extension.config import MyConfig
from my_extension.view import MySemanticView


@semantic_layer(
id="my_platform",
name="My Data Platform",
description="Connect to My Data Platform's semantic layer",
)
class MySemanticLayer(SemanticLayer[MyConfig, MySemanticView]):
configuration_class = MyConfig
...

See Semantic Layers Extension Point for implementation details.

Personal OAuth2 connections​

Providers can expose a personal connection action by implementing get_configuration_actions(configuration) and execute_configuration_action(action_id, configuration, return_url). The first hook returns SemanticLayerAction entries describing whether the authenticated user is connected. The second returns a SemanticLayerActionResult containing the provider's authorization URL. Providers without connection actions can keep the default implementations.

Store access and refresh tokens using the Python-only get_context().storage.secrets accessor. Never put personal credentials in the shared layer configuration, action results, query results, logs, or exceptions. The host executes provider methods under the owning extension and requesting user's context, including background chart work. Semantic View query results, cached dimension values, and shared async query tasks are partitioned by user, including providers without connection actions. This reduces cache sharing for providers with identical results for all users, but declaring no actions does not establish that a provider returns user-independent data.

When any provider operation requires authentication, raise the core exception:

from superset_core.semantic_layers.layer import SemanticLayerAuthenticationRequiredError

raise SemanticLayerAuthenticationRequiredError("oauth2")

Superset translates this into the existing OAUTH2_REDIRECT error contract for view discovery, metadata, filter values, and chart queries. The authorization link opens a protected start route, which checks access to the originating layer or specific view before invoking the provider's action. A grant on one view is sufficient to connect a personal account; it does not grant access to sibling views or permission to edit the layer.

The host supplies a completion URL as return_url. The provider must preserve that URL in its server-side OAuth state and redirect there after validating the callback and durably saving the authenticated user's tokens. OAuth state, PKCE validation, token exchange, refresh, and revocation remain the provider's responsibility. The host completion page sends a correlation ID through BroadcastChannel and the storage-event fallback; it never sends credentials. The original tab then refreshes the configuration form or retries the failed operation. Returning browser focus before authorization completes does not consume the completion notification. Closing an unfinished connection window allows the user to start another attempt.

The completion URL uses the request's externally visible host and scheme. Operators must configure their reverse proxy, forwarded headers, and allowed hosts so Superset sees its trusted public HTTPS origin. See the reverse proxy configuration.

Action POST responses contain result.redirect_url and a host-generated result.tab_id. Both the configuration modal and the generic OAuth error UI use the same completion listener. No access or refresh token is returned in these responses.