dbt-metabase: pushing dbt model metadata into Metabase
dbt + Metabase integration
At a glance
- What is it?
- dbt-metabase reads a compiled dbt manifest and writes what it finds into the Metabase data model, so primary keys become entity keys, relationship tests become foreign keys, column descriptions appear in Metabase, and Metabase questions and dashboards come back out as dbt exposures.
- Who is it for?
- dbt-metabase fits a data team that treats dbt as the source of truth for schema and uses Metabase as the analytics layer, because the tool reads the compiled manifest rather than a second description of your models, which means the tests you already wrote become the foreign keys and the column docs you already wrote become the Metabase descriptions.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 17 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The direction of travel: dbt in, Metabase metadata out
dbt-metabase is an integration between dbt and Metabase, and the premise is that dbt is your source of truth for database schemas while Metabase is your analytics tool. From that premise the tool does two things. It propagates table relationships, model and column descriptions, and semantic types such as currency, category and URL, into the Metabase data model. And it goes the other way, extracting Metabase questions and dashboards as exposures in your dbt project. That second direction is the one that is less common in tooling and worth thinking about, because exposures are how a dbt project records which downstream things depend on which models, and pulling them from Metabase means the lineage is derived from where dashboards actually live rather than maintained by hand. The package is on PyPI, the project is MIT licensed, and the last push to the repository was on 2026-10-06.
Installing and authenticating
The install is a single pip command.
pip install dbt-metabasePython 3.10 or above is required, and for development the project expects uv to be installed. The command line entry point is dbt-metabase, and the full option list is available from the tool itself.
dbt-metabase --helpEvery command needs to authenticate against the Metabase API, and there are two ways to do it. An API key passed with the metabase-api-key option is strongly recommended for automation, and the documentation points out that API keys are available in Metabase 49 or later. The fallback is a username and password pair, which the project describes as the option for older versions of Metabase and smaller instances. That distinction matters for automation, because a password in a CI configuration is a worse thing to have lying around than a scoped key, and the reason the project recommends the key is not fashion.
The manifest is the input, and it has to be compiled first
Before any of this runs, dbt-metabase needs a compiled manifest.json to parse. That file is one of the dbt artifacts generated during compilation, and once dbt compile finishes it can be found in the target/ directory of your dbt project. This is the design decision that makes the tool work well. Because the input is the compiled manifest rather than a hand-written configuration file, dbt-metabase sees the same model metadata, the same test definitions and the same resolved references that dbt itself sees, including the aliases and the ref targets. It also means the tool has to run after a compile, and it means the artefact on disk is a large JSON file that reflects the state of the project at compile time, so a stale manifest produces a stale Metabase model. The project links to the dbt documentation on running a dbt project for the broader context.
What a models run actually changes in Metabase
The example in the project overview defines a short schema.yml with two models, stg_users and stg_groups, with primary key tests, a unique test, a relationship test from group_id to groups, and descriptions on every column. Running the models command against that project is enough to propagate the primary keys, the foreign keys and the descriptions.
dbt-metabase models \
--manifest-path target/manifest.json \
--metabase-url https://metabase.example.com \
--metabase-api-key mb_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX= \
--metabase-database business \
--include-schemas publicThe result is visible in Metabase under Settings, then Admin Settings, then Table Metadata, where the id column of stg_users is marked as an Entity Key and group_id is marked as a Foreign Key pointing at id in stg_groups. The include-schemas option is worth noting as a safety valve, since it limits which schemas in the database the tool will touch, so pointing it at a database with many schemas does not mean it will rewrite all of them.
Foreign keys, and when to override dbt's own answer
The preferred way to declare a foreign key in dbt-metabase is the way you already declare it in dbt, through native relationship tests and column-level constraints. But those are not always enough, and the tool gives you an override. You can set fk_target_table and fk_target_field as meta fields, and if both are set for a column the meta fields take precedence over the test-derived relationship. The target table can be given as schema_name.table_name or as just table_name to mean the current schema, and if your model has an alias you should provide that alias rather than the original name. The alias point is a real trap, because dbt-metabase is looking at the compiled manifest where the model may be exposed under a different name, and pointing it at the wrong name produces a relationship that Metabase displays but that does not resolve.
Semantic types and visibility, the parts that shape the question builder
Semantic types are what stop Metabase from treating every column as generic text, and they are set with a meta field on the column. The listing of accepted values is long and specific: type/PK, type/FK, type/Number, type/Currency, type/Category, type/Title, type/Description, type/City, type/State, type/ZipCode, type/Country, type/Latitude, type/Longitude, type/Email, type/URL, type/ImageURL, type/SerializedJSON and type/CreationTimestamp. These were formerly known as special types, and Metabase's own field types documentation has the complete list. Visibility is the other half. A column can be set to normal, which is the default and displays the field normally in tables and charts, details-only, which shows it only when viewing the details of a single record, or sensitive, which hides it and makes it unselectable in questions created with the graphical interface. Tables take no value for visible, which is the default, or hidden, technical or cruft. That last set is the interesting one, because marking a table as cruft is how you keep staging models out of the analytics tool without deleting them from the warehouse.
Other meta fields, and the ones that carry prose
Beyond foreign keys, semantic types and visibility, the tool passes through a further set of meta fields, and two of them carry text rather than an enum. There is a display_name that lets a model or column appear under a different name in Metabase, which is the escape hatch for a staging model that should read as something a business user recognises. There are points_of_interest, described as relevant records, and caveats, described as sensitive information about users. A column can also set has_field_values to list, which tells Metabase to maintain a list of distinct values for the field, and that is what powers the filter dropdowns in the question builder. The project notes that if you notice changes to the accepted values you should submit a pull request with an update, which tells you the set of recognised keys is something the project maintains against the Metabase documentation rather than something it discovered once.
How the project is built and tested
The repository is a small Python package with the dbtmetabase/ directory as the only package, a pyproject.toml using setuptools with setuptools-scm for the version, and a sandbox/ directory that runs the tool against a real Metabase and Postgres in Docker. The Makefile is built around uv, with a dependencies target that syncs without installing the project, a build target that produces the distributions, a check target that runs the lint and type checks together, a test target that clears tests/tmp and runs pytest, and a dist-check that runs twine check over the built artefacts. The linting is ruff with a rule selection that includes pycodestyle, pyflakes, isort, flake8-builtins, flake8-bugbear, flake8-comprehensions, flake8-fixme and pyupgrade, and the type checking is pyright over the dbtmetabase package. The dev dependencies include dbt-core at version 1.11.2 and dbt-postgres at 1.10.0, so the test suite runs against a real dbt rather than a fixture of one.
Editorial conclusion
dbt-metabase fits a data team that treats dbt as the source of truth for schema and uses Metabase as the analytics layer, because the tool reads the compiled manifest rather than a second description of your models, which means the tests you already wrote become the foreign keys and the column docs you already wrote become the Metabase descriptions. It does not fit a team that wants Metabase and dbt to stay independent, because running it makes the two tools share a vocabulary, and it does not fit an older Metabase instance that has no API key support, where the fallback is a username and password. Before you run it, note that a compiled manifest.json is required, and that the visible result in Metabase is in Settings under Admin Settings and Table Metadata, so you should check that screen rather than only the dashboards.
Frequently asked questions
What does dbt-metabase do?
It propagates dbt table relationships, model and column descriptions and semantic types into the Metabase data model, and extracts Metabase questions and dashboards as exposures in your dbt project. It reads a compiled dbt manifest rather than a separate configuration file.
How do I authenticate dbt-metabase against Metabase?
Every command needs Metabase API authentication. An API key passed with the metabase-api-key option is strongly recommended for automation and is available in Metabase 49 or later. A username and password pair is the fallback for older Metabase versions and smaller instances.
How do I override a foreign key in dbt-metabase?
Set the fk_target_table and fk_target_field meta fields on the column. If both are set they take precedence over the relationship derived from dbt tests. The target table can be schema_name.table_name or table_name for the current schema, and if the model has an alias you should give the alias rather than the original name.
Which visibility types can a dbt-metabase column use?
For columns, normal is the default and displays the field normally, details-only shows it only in the details of a single record, and sensitive hides it and makes it unselectable in questions built with the graphical interface. Tables take no value for visible, which is the default, or hidden, technical or cruft.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/gouline-dbt-metabase)Was this useful?