Safeguard
Developer Tools•

How do you pin dbt packages so every run installs the same code?

Steps to pin dbt packages: exact versions, full commit hashes, a committed package-lock.yml, and a deliberate upgrade routine that you can review.

Safeguard Security Team
3 min read

Pin dbt packages by using exact versions for Hub packages, full commit hashes for Git packages, and a committed package-lock.yml file. Then run an upgrade only as a reviewed change. With those three habits, a scheduled dbt run on Tuesday installs the same package code as the one you tested on Monday.

Why unpinned packages bite

If a package entry is a loose range or a moving branch, a fresh dbt deps can pull different code from the one you reviewed. In a data project that can mean a changed macro quietly rewriting a model, or, in the worst case, a compromised release reaching your warehouse on the next scheduled run.

The dbt docs say that a branch is pinned to its head commit at install time, and that a version range is pinned to the latest matching release. Both are snapshots of a moving target, which is why the lock file matters.

Steps

  1. Choose exact references. For a Hub package, use a specific version. For Git, use a full 40 character commit hash as the revision.
packages:
  - package: dbt-labs/dbt_utils
    version: 1.3.0
  - git: "https://github.com/example-org/internal-macros.git"
    revision: 4f9c2d7e1a0b3c5d6e7f8091a2b3c4d5e6f70812

The names above are examples, so use your own packages and versions.

  1. Run the install. Running dbt deps creates or updates package-lock.yml in the project root.
  2. Commit the lock file. Do not add it to .gitignore. The docs note that gitignoring it means each dbt deps can pull new versions.
  3. Install from the lock in CI and production. If your package file has not changed, later runs install from the lock.
  4. Upgrade deliberately. To get newer commits or versions, use the upgrade option on dbt deps in a branch, read the diff of the lock file and the package changes, then merge.
  5. Rebuild when needed. The docs say that after changing a version or revision you may need a full refresh of affected models.

What a reviewer should see in the pull request

A good package upgrade pull request shows the lock file diff, a changelog link, and a short note on macros that changed. If you cannot say what changed, you cannot say what runs against your warehouse.

Pitfalls

Removing an entry from the package file does not delete its folder. The docs say to delete the directory, or run a clean followed by a fresh install. A stale folder can keep old code around.

Also remember the Git warning. Packages without a revision trigger a warning, and the docs say that silencing it with warn-unpinned: false is not recommended.

Quick check

Should package-lock.yml be committed?

Yes. It is what keeps installs reproducible. The docs warn that ignoring it lets each install pull new versions.

Is a version range acceptable?

It is allowed, but the lock file freezes the resolved release. Without a committed lock, a range can drift.

Safeguard's dependency scanning reads manifests and lockfiles and flags known vulnerable components, with a free scan at gold.safeguard.sh/scan.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.