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
- 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.
- Run the install. Running
dbt depscreates or updatespackage-lock.ymlin the project root. - Commit the lock file. Do not add it to
.gitignore. The docs note that gitignoring it means eachdbt depscan pull new versions. - Install from the lock in CI and production. If your package file has not changed, later runs install from the lock.
- Upgrade deliberately. To get newer commits or versions, use the upgrade option on
dbt depsin a branch, read the diff of the lock file and the package changes, then merge. - 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.