The dbt docs recommend native private packages over the token method. Native packages use your existing Git integration on the dbt platform, or your SSH configuration locally, while the token method needs a shared user and a token that can expire. Native avoids a long-lived secret sitting in your package file.
The two methods
The dbt packages documentation describes both.
Native private packages use the private key with the repository path and a provider, such as GitHub, GitLab or Azure DevOps. On the dbt platform they use the Git integration you already set up. Locally, newer dbt versions use your SSH configuration and need the provider key set. You can still pin them with a revision.
The token method puts a Git URL in the package file and injects a token through an environment variable. The docs note the variable names must carry the dbt prefix, and secret ones use the secret environment prefix, case sensitive.
What the docs warn about tokens
Two warnings stand out.
- Be careful of the expiration date of any token, because an expired token can break scheduled runs.
- User tokens create problems if the user loses repository access.
The docs also say native private packages are recommended instead, since the token method requires extra setup such as creating a user and sharing a token.
The security comparison
| Question | Native private package | Git token in the URL |
|---|---|---|
| Who owns the credential | Your existing Git integration | A user or service account you create |
| Expiry risk | Tied to the integration | Token expiry can break runs |
| Where the secret lives | Integration settings | Environment variable on the job |
| Departure risk | Less dependent on one person | Breaks if the token owner loses access |
| Rotation work | Handled in the integration | Manual, on a schedule you must keep |
This is a reading of the docs, not a claim about a specific deployment. Check how your own setup behaves.
If you must use a token
- Use a dedicated service account, not a person's account.
- Give it read access to only the packages repository.
- Set a calendar reminder before expiry, and name an owner.
- Store the token as a secret environment variable and confirm it does not appear in logs. The dbt docs separate normal and secret variables for this reason.
- Pin the package with a revision, a tag or a full commit hash, not a moving branch.
- Commit the lock file so each environment gets the same resolved versions.
Do not forget the code itself
A private package is still code that runs in your project. It can contain macros that run SQL in your warehouse. Review changes to it with the same care as your own models, and see the earlier post on what a macro can do.
Safeguard's SBOM and dependency scanning can inventory the packages a dbt project lists, and its policies can flag unpinned ones. The free scan at https://gold.safeguard.sh/scan is a quick way to try it.
Quick check
Can I pin a native private package?
Yes. The docs say you can pin them with a revision.
Does a token in an environment variable stay hidden?
Only if your tooling masks it. dbt distinguishes secret variables by a prefix, and you should still check your logs.
Sources
Last reviewed: 19 October 2026.