How to Add Support for a New Database Dialect in Superset's db_engine_specs: A Complete Guide

To add support for a new database dialect in Apache Superset, create a Python module in superset/db_engine_specs/ containing a class that inherits from BaseEngineSpec, define the required engine attributes and metadata, and Superset's autodiscovery system will automatically register the dialect without any manual registration steps.

Adding support for a new database dialect allows Apache Superset to generate dialect-specific SQL, handle connection parameters, and expose database-specific features in the UI. This process leverages the db_engine_specs plugin architecture, where each database backend is represented by an engine spec class that defines how Superset interacts with that specific SQL dialect.

Understanding the db_engine_specs Architecture

Superset discovers database-specific behavior through engine spec classes that inherit from BaseEngineSpec (defined in superset/db_engine_specs/base.py at line 324). The base class provides default implementations for SQL generation, schema inspection, and error handling, while individual dialects override specific methods to customize behavior.

The autodiscovery mechanism relies on two key functions in superset/db_engine_specs/__init__.py:

  • load_engine_specs() (line 62): Iterates through all modules in superset/db_engine_specs/ using pkgutil.iter_modules and imports any class that satisfies is_engine_spec()
  • get_engine_spec(backend, driver) (line 89): Looks up the appropriate spec by calling supports_backend() on each loaded class until it finds a match

This means you only need to create the spec file and define the class correctly—no manual registration is required.

Step-by-Step Implementation Guide

Step 1: Create the Engine Spec Module

Create a new Python file under superset/db_engine_specs/. The filename is arbitrary (e.g., mydb.py), but the class inside must inherit from BaseEngineSpec or a mixin like BasicParametersMixin.

Ensure the file includes the Apache license header:


# superset/db_engine_specs/mydb.py

# Licensed to the Apache Software Foundation (ASF) under one

# or more contributor license agreements.  See the NOTICE file

# distributed with this work for additional information

# regarding copyright ownership.  The ASF licenses this file

# to you under the Apache License, Version 2.0 (the "License");

# you may not use this file except in compliance with the License.

# You may obtain a copy of the License at

#   http://www.apache.org/licenses/LICENSE-2.0

Step 2: Define the Core Engine Spec Class

Define the class with the required identification attributes. The engine attribute must match the SQLAlchemy dialect name (the string before :// in the connection URL).

from __future__ import annotations

from superset.db_engine_specs.base import BaseEngineSpec, DBEngineSpecMetadata

class MyDBEngineSpec(BaseEngineSpec):
    """Engine spec for MyDB – a fictional column‑store database."""

    # Identification

    engine = "mydb"                     # SQLAlchemy backend name

    engine_name = "MyDB"                # Display name in UI

    engine_aliases = {"mydb_legacy"}    # Optional alternate names

    drivers = {"mydriver": "MyDB driver"}  # Map driver name → description

    default_driver = "mydriver"
    
    # Connection string placeholder shown in UI

    sqlalchemy_uri_placeholder = (
        "mydb+mydriver://user:password@host:port/dbname[?key=value]"
    )

The supports_backend method in BaseEngineSpec checks these attributes to determine if this spec handles a given connection URL.

Step 3: Add Documentation Metadata

Populate the metadata attribute with a DBEngineSpecMetadata TypedDict. This centralizes UI-display information and eliminates the need to touch multiple configuration files.

    metadata: DBEngineSpecMetadata = {
        "description": "MyDB is a fast column‑store DB for analytical workloads.",
        "logo": "mydb.svg",
        "homepage_url": "https://mydb.example.com/",
        "categories": ["Analytical Databases", "Open Source"],
        "pypi_packages": ["mydriver"],
        "connection_string": "mydb+mydriver://{username}:{password}@{host}:{port}/{database}",
        "default_port": 1234,
        "parameters": {
            "username": "Database username",
            "password": "Database password",
            "host": "Database host",
            "port": "Default 1234",
            "database": "Database name",
        },
    }

Step 4: Implement Custom SQL Behavior

Override methods and attributes to handle dialect-specific SQL generation. Common customizations include:

Time-grain expressions for date truncation:

    from superset.constants import TimeGrain

    _time_grain_expressions = {
        None: "{col}",
        TimeGrain.SECOND: "DATE_TRUNC('second', {col})",
        TimeGrain.MINUTE: "DATE_TRUNC('minute', {col})",
        TimeGrain.HOUR: "DATE_TRUNC('hour', {col})",
        TimeGrain.DAY: "DATE_TRUNC('day', {col})",
    }

Column type mappings to convert native types to Superset's generic types:

    import re
    from superset.utils.core import GenericDataType

    column_type_mappings = (
        (re.compile(r"^mydb_int$", re.IGNORECASE),
         None,  # Use SQLAlchemy generic type

         GenericDataType.NUMERIC),
        (re.compile(r"^mydb_varchar$", re.IGNORECASE),
         None,
         GenericDataType.STRING),
    )

Error handling by mapping regex patterns to SupersetError objects in the custom_errors dictionary.

Step 5: Verify Autodiscovery

No manual registration is required. The load_engine_specs function in superset/db_engine_specs/__init__.py automatically imports your module and the get_engine_spec function matches it using supports_backend.

When a user creates a database connection with a URL like mydb://..., Superset calls:


# From superset/db_engine_specs/__init__.py

def get_engine_spec(backend: str, driver: Optional[str] = None) -> type[BaseEngineSpec]:
    engine_specs = load_engine_specs()
    # Driver-aware lookup

    if driver is not None:
        for spec in engine_specs:
            if spec.supports_backend(backend, driver):
                return spec
    # Backend-only fallback

    for spec in engine_specs:
        if spec.supports_backend(backend):
            return spec
    return BaseEngineSpec

Your class will be selected if engine == "mydb" or if the backend matches any of your engine_aliases.

Testing Your New Database Dialect

Create unit tests to verify your engine spec behaves correctly:


# tests/unit_tests/db_engine_specs/test_mydb.py

from superset.db_engine_specs.mydb import MyDBEngineSpec

def test_mydb_engine_name():
    assert MyDBEngineSpec.engine_name == "MyDB"
    assert MyDBEngineSpec.engine == "mydb"
    assert MyDBEngineSpec.supports_backend("mydb")
    assert MyDBEngineSpec.supports_backend("mydb_legacy")  # alias test

def test_time_grain_expressions():
    spec = MyDBEngineSpec
    assert spec._time_grain_expressions is not None

Run the test suite with:

pytest tests/unit_tests/db_engine_specs/test_mydb.py -v

Before submitting, run pre-commit run --all-files to ensure the Apache license header is present and code formatting complies with the project standards.

Summary

  • Create a module in superset/db_engine_specs/ (e.g., mydb.py) containing a class that inherits from BaseEngineSpec.
  • Define identification attributes including engine, engine_name, engine_aliases, and drivers so Superset can match your dialect to connection URLs.
  • Add metadata using DBEngineSpecMetadata to provide UI documentation, connection string templates, and parameter descriptions.
  • Implement custom behavior by overriding methods for time-grain expressions, column type mappings, error handling, and schema management.
  • Rely on autodiscovery—Superset automatically loads your spec via load_engine_specs and matches it using supports_backend without requiring manual registration.
  • Test your implementation with unit tests in tests/unit_tests/db_engine_specs/ and run pre-commit checks before contributing.

Frequently Asked Questions

What is the minimum required configuration for a new engine spec?

At minimum, you must create a class inheriting from BaseEngineSpec and define the engine attribute (matching the SQLAlchemy dialect name) and engine_name (the display name). The supports_backend method in the base class uses these attributes to determine if your spec handles a given connection URL. Without these, Superset cannot discover or identify your dialect.

How does Superset automatically discover new database dialects?

Superset uses the load_engine_specs function in superset/db_engine_specs/__init__.py to iterate through all Python modules in the superset/db_engine_specs/ directory using pkgutil.iter_modules. It imports each module and collects any class that satisfies is_engine_spec (typically classes inheriting from BaseEngineSpec). When a user creates a database connection, get_engine_spec matches the URL against loaded specs using supports_backend.

Can I extend an existing engine spec instead of creating a new one?

Yes, you can inherit from existing engine specs rather than BaseEngineSpec. For example, if your database is PostgreSQL-compatible, you can inherit from PostgresEngineSpec in superset/db_engine_specs/postgres.py and only override the methods that differ. This approach reduces code duplication and ensures you inherit tested behavior for standard SQL operations while customizing only the dialect-specific features your database requires.

Where should I place tests for my custom engine spec?

Place unit tests in tests/unit_tests/db_engine_specs/ following the naming convention test_<dialect>.py. For integration tests that require a live database connection, use tests/integration_tests/db_engine_specs/. Reference existing test files like test_postgres.py for patterns on testing time-grain generation, column type mapping, and backend support detection. Run tests with pytest tests/unit_tests/db_engine_specs/test_mydb.py and ensure all new files include the Apache license header by running pre-commit run --all-files.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →