ServicesAboutNotesContact Get in touch →
EN FR
Note

dbt Hub Publishing

How to publish a dbt package to the dbt Hub — requirements, the registration process, hubcap automation, and best practices for version management.

Planted
dbtdata engineering

The dbt Hub is the standard distribution channel for open-source dbt packages — a registry, not a hosting platform. Packages live on GitHub; the Hub indexes their releases. As of early 2026, the ecosystem has over 400 packages covering source-specific transformations (Fivetran packages), testing utilities (dbt-utils, dbt-expectations), and monitoring tools (Elementary).

Requirements

Publishing to the Hub requires three things:

  1. The package is hosted on a public GitHub repository
  2. It has a dbt_project.yml with a name field
  3. Releases use semantic versioning tags (e.g., v0.1.0)

That’s it. No special metadata, no separate manifest, no approval process beyond the initial PR.

The Registration Process

Getting your first version on the Hub is a four-step process:

  1. Create a GitHub release with a semver tag. Tags like first-release, beta, or latest are ignored by the Hub’s indexer. Use v0.1.0, v1.0.0, etc.

  2. Open a pull request on the hub.getdbt.com repository to add your package to the index. The PR adds your repository to a JSON manifest.

  3. Wait for review. PRs are typically approved within one business day. The dbt Labs team does a basic sanity check — valid dbt_project.yml, semver tags, public repo.

  4. Automatic updates after that. A script called hubcap runs hourly to detect new GitHub releases automatically. No further PRs needed for version updates.

Once registered, new releases are picked up by hubcap within an hour of you creating a GitHub release. The cycle becomes: tag a release, push it, and the Hub updates itself.

How Users Install Hub Packages

Once published, users install your package with a version range in their packages.yml:

packages.yml
packages:
- package: your-namespace/my_package
version: [">=0.1.0", "<1.0.0"]

The namespace is typically your GitHub username or organization. The version range lets dbt resolve the best compatible version automatically.

The Transitive Dependency Advantage

Hub packages have one significant advantage over Git packages: automatic transitive dependency resolution.

If your package depends on dbt-utils and the user’s project also depends on dbt-utils, the Hub reconciles version conflicts automatically. It picks the highest version that satisfies all constraints. Git packages can’t do this — version conflicts between Git dependencies require manual resolution, and the error messages are often cryptic.

This matters in practice because most non-trivial packages depend on dbt-utils. When a user has five packages installed and all five depend on dbt-utils, the Hub finds one version that works for everyone. With Git dependencies, you’d need to manually ensure compatibility.

Best Practices

The hubcap documentation lays out practices that the dbt Labs team has refined from maintaining the ecosystem:

Set require-dbt-version

require-dbt-version: [">=1.3.0", "<3.0.0"]

Users should know compatibility upfront. Without this, someone on dbt 1.1 gets cryptic compilation errors instead of a clear “incompatible version” message. With the Fusion engine (dbt 2.0) now available, setting [">=1.3.0", "<3.0.0"] covers both runtimes.

Declare Hub Dependencies When Possible

If your package depends on dbt-utils, reference it from the Hub, not from Git:

# Good — enables transitive resolution
packages:
- package: dbt-labs/dbt_utils
version: [">=1.0.0", "<2.0.0"]
# Avoid — breaks transitive resolution
packages:
- git: "https://github.com/dbt-labs/dbt-utils.git"
revision: v1.3.0

Hub dependencies participate in version resolution. Git dependencies don’t.

Use Wide Version Ranges

Don’t pin to patch versions. version: "1.3.0" forces every user to use exactly that version and creates conflicts with other packages that also depend on dbt-utils but expect a different patch.

# Too tight — creates dependency conflicts
- package: dbt-labs/dbt_utils
version: "1.3.0"
# Better — allows flexibility
- package: dbt-labs/dbt_utils
version: [">=1.0.0", "<2.0.0"]

The wider the range that actually works, the fewer headaches for your users.

Don’t Override Global Behavior

Your package should not override dbt Core behavior that affects resources outside your package. Overriding generate_schema_name or generate_alias_name in a package changes behavior for the user’s entire project, not just your models. If you need custom behavior, scope it to your own models using the config() block.

Prefer Built-in Cross-Database Macros

Since dbt-utils v1.0, cross-database macros like datediff, dateadd, safe_cast, and hash live in the dbt namespace. Use {{ dbt.datediff(...) }} instead of reimplementing date arithmetic yourself. This reduces your dependency footprint and takes advantage of adapter-specific implementations that dbt Core maintains.

Semantic Versioning for Packages

Follow semver strictly:

  • Patch (0.1.0 → 0.1.1): Bug fixes only. No behavior changes.
  • Minor (0.1.0 → 0.2.0): New models, new macros, new features. Existing behavior unchanged.
  • Major (0.2.0 → 1.0.0): Breaking changes — renamed models, removed macros, changed output schemas.

Pre-1.0 packages (0.x.y) can treat minor versions as breaking, which is common while you’re finding the right API. Once you hit 1.0.0, you’re committing to stability.

Maintain a CHANGELOG.md that documents what changed in each version. Users need to know whether upgrading from 0.3.0 to 0.4.0 is safe or requires migration steps.

When Not to Use the Hub

Not every package belongs on the Hub. Internal packages with proprietary business logic, packages that only work against a specific company’s data, and experimental packages that aren’t ready for community use are better distributed as Git packages. The Hub is for packages that solve a problem the broader community shares.