Skip to content

Adapters

Overview

Supported database engines and their connection configuration.

SQLBuild uses adapters to connect to different database engines.

Adapter Status Install
DuckDB Supported included by default
MotherDuck Supported included by default (uses DuckDB)
Snowflake Supported sqlbuild[snowflake]
BigQuery Supported sqlbuild[bigquery]
Databricks Supported sqlbuild[databricks]
PostgreSQL Supported sqlbuild[postgres]
SQL Server Supported sqlbuild[sqlserver]
ClickHouse Coming soon
Redshift Coming soon
Trino Coming soon
Spark Coming soon
Athena Coming soon

Set the adapter in sqlbuild_project.toml:

name = "my_project"
adapter = "duckdb"

Or override it per developer in sqlbuild_local.toml:

adapter = "duckdb"

You can write your own adapter for any database engine by placing Python files under adapters/ in your project directory.

The most common case is extending an existing adapter with custom behavior. Subclass the built-in adapter, set a new adapter_name, and override what you need:

adapters/duckdb_plus.py
from sqlbuild.integrations.duckdb.client import DuckDbAdapter
class DuckDbPlusAdapter(DuckDbAdapter):
adapter_name = "duckdb_plus"
def connect(self, config):
connection = super().connect(config)
# custom setup - load extensions, set pragmas, etc.
self.execute(connection, "SET enable_progress_bar = true")
return connection
adapter = "duckdb_plus"

For a database engine with no built-in support, subclass BaseAdapter. It provides ANSI SQL defaults for most methods - you only need to implement connect, execute, close, and any methods where your engine differs from standard SQL:

adapters/my_database.py
from sqlbuild.adapter.base.base_adapter import BaseAdapter
class MyDatabaseAdapter(BaseAdapter):
adapter_name = "my_database"
sql_analysis_dialect_name = "postgres" # SQL dialect for validation and lineage
def connect(self, config):
...
def execute(self, connection, sql):
...
def close(self, connection):
...

Set sql_analysis_dialect_name to the SQL dialect name that matches your engine’s SQL syntax. This enables compile-time SQL validation, column inference, column lineage, and local scenario replay for your adapter. If omitted, SQLBuild uses generic SQL parsing. SQL analysis is powered by Polyglot, a Rust reimplementation of SQLGlot supporting 32+ dialects.

For full control with no inherited defaults, subclass StrictAdapter instead. Every method is abstract and must be implemented explicitly. SQLBuild raises a clear error listing any unimplemented methods.

  • SQLBuild discovers all .py files under adapters/ recursively (excluding __init__.py and files starting with _)
  • Each file is scanned for classes that define a string adapter_name and subclass StrictAdapter (or any of its subclasses like BaseAdapter or a built-in adapter)
  • Adapter names must be unique across all adapter files - duplicates raise an error
  • Custom adapter names cannot shadow built-in names (duckdb, snowflake, bigquery, databricks, postgres, sqlserver)
StrictAdapter (fully abstract - all methods must be implemented)
└── BaseAdapter (ANSI SQL defaults - override only what differs)
├── DuckDbAdapter
├── SnowflakeAdapter
├── BigQueryAdapter
├── DatabricksAdapter
├── PostgresAdapter
└── SqlServerAdapter

StrictAdapter composes four mixins that define the full adapter contract:

  • ConnectionMixin - connect, close, begin, commit, rollback
  • SchemaMixin - relation_exists, list_relations, describe_relation, ensure_schema
  • MaterializationMixin - create_table_as, create_view, drop, rename, swap, load_seed
  • DiffMixin - diff_schema, diff_rows, sample_unequal_rows, sample_side_only_rows