Rust 1.100.0 landed on 12 November 2026 and stabilized dependency cooldowns in Cargo, so a crate version published an hour ago can be made invisible to the resolver until it has aged. By the end of this you will have a three-day window on third-party crates, a probe that proves which state you are actually in, and the four routes that walk past the window either closed or named.

The short version: put global-min-publish-age = "3 days" under [registry] in .cargo/config.toml, run cargo update --dry-run, and look for the string as of min-publish-age in the output. The 1.100 release announcement calls the feature "min-publish-age"; the key that stable Cargo actually reads is registry.global-min-publish-age, defined in the Cargo config reference, and that is the spelling used throughout here. If you piloted the feature on nightly, the bare registry.min-publish-age key was deleted in this same release by PR #17353.

PathDoes the cooldown apply?What to do about it
cargo update, or a build resolving a version that is not pinnedYes. Versions newer than the window are ignored by the resolverLeave resolver.incompatible-publish-age at its default, deny
A version already recorded in Cargo.lockNo. The check gates entry into the lockfile, not residence in itReview lock diffs in code review as before
cargo install <tool>, including its dependenciesNo, stated outright in the 1.100 announcementPin cargo install name@version to a version older than your window
A registry whose index entries carry no pubtime fieldNo, and nothing is printedCurl one index entry and confirm the field exists
A toolchain older than 1.100 reading the same config fileNo. Both keys are documented as "Respected as of 1.100+"Pin rust-toolchain.toml and the CI image tag

This is for anyone running cargo build on a shared runner who wants a waiting period before new versions reach the lockfile. Cargo has no install-script allowlist at all, and the npm equivalent it would resemble fails ten different ways; a cooldown buys the scanners and the community time rather than preventing execution.

Prerequisites

  • Rust 1.100.0 or newer, via rustup update stable. Confirm with cargo -V, which should print cargo 1.100.0 or later.
  • A crate or workspace with a committed Cargo.lock.
  • A registry that records publish times. crates.io does: the pubtime field landed behind an environment toggle in crates.io #12315, and the toggle was removed in #14515 on 26 August 2026, so index entries now carry it unconditionally, backfilled to 2015-era versions.
  • curl, for the index check in step 4.
  • Write access to the repo's .cargo/config.toml, or to the user-level $CARGO_HOME/config.toml if you want the policy across every checkout on a machine.

Step-by-step

1. Write the stable key, not the nightly one

# .cargo/config.toml
[registry]
global-min-publish-age = "3 days"

The accepted value is an integer plus seconds, minutes, hours, days, weeks, or months. "0" allows everything, and "0" is also the default, so an untouched 1.100 toolchain resolves exactly as 1.99 did. Cargo does not reject a stale registry.min-publish-age line left over from a nightly pilot, so grep your repos for that bare key before assuming the pilot is still in force.

2. Pin the toolchain that reads the file

# rust-toolchain.toml
[toolchain]
channel = "1.100.0"

A rust:1.99-slim image parses the same .cargo/config.toml, ignores the age key without a warning, and resolves whatever is newest. Pin the base image tag in the same commit as the config change, since floating tags move on someone else's schedule: ubuntu-latest becomes Ubuntu 26.04 on 19 November.

3. Re-resolve and read the hold-back line

cargo update --dry-run

--dry-run reports what would change without writing the lockfile. When a version is held back, Cargo names it. From the 1.100 announcement:

$ cargo update
    Updating crates.io index
 Locking 2 packages to highest compatible version as of min-publish-age
  Adding cc v1.11.0 (available: v1.18.0, published 3 hours ago)
  Adding clap 4.6.7 (available: 4.6.9, published 2 days ago)

The phrase worth grepping for is as of min-publish-age. Its absence means nothing was eligible for hold-back on that run, so treat the string as a positive signal only, never as evidence the setting is off.

4. Prove the registry carries publish times

curl -s https://index.crates.io/ar/ra/arrayref | tail -1

The last line of that sparse-index file ends with "yanked":false,"pubtime":"2024-09-14T12:24:40Z". The format is a subset of ISO 8601 (yyyy-mm-ddThh:mm:ssZ, no fractional seconds, always Z) per the registry index reference. Run the same curl against your internal registry's index path. The announcement is blunt about the missing case: "Versions without a pubtime field in the index are never held back." A self-hosted Artifactory, Cloudsmith or kellnr index that predates pubtime support passes every version straight through, and registries.<name>.min-publish-age is documented as "ignored if the registry does not support this".

5. Set zero for your own crates

[registries.internal]
index = "sparse+https://crates.internal.example/api/v1/crates/"
min-publish-age = "0"

A cooldown on first-party crates delays your own release train and buys no security, because you control the publish. The per-registry key overrides the global one, and its environment form is CARGO_REGISTRIES_INTERNAL_MIN_PUBLISH_AGE, with the registry name uppercased in the variable.

6. Keep an override that does not disarm the policy

CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow cargo update clap --precise 4.6.9

resolver.incompatible-publish-age takes allow or deny and defaults to deny, so a patch released an hour ago can be taken for one command without editing a file anyone else will inherit. Cargo prints the exception on the line it reports: Updating clap 4.6.7 -> clap 4.6.9 (published 2 days ago, minimum age 3 days). The resolver reference states that denied versions are ignored "unless they already exist in the Cargo.lock file", and per the announcement the override is sticky: the newer version stays until a later cargo update re-resolves it.

Candidate version in the indexpubtime present?Eligible for selectionage < min-publish-age?already in Cargo.lock?incompatible-publish-ageIgnored by the resolvernoyesnoyesyesnoallowdeny

Verify it works

Use a scratch crate and a window wide enough that something has to be caught:

cargo new /tmp/cooldown-probe && cd /tmp/cooldown-probe
cargo add clap
printf '[registry]\nglobal-min-publish-age = "100 weeks"\n' > .cargo/config.toml
cargo update --dry-run

With a two-year window, any crate that has shipped a release since then produces a (available: ..., published ...) line, and the run prints Locking with as of min-publish-age. Drop the value to "0", run the same command, and the hold-back line disappears while the newest versions return to the output. Two runs, one changed value, one behavioural difference.

There is a gap here worth naming instead of papering over: no stable command prints the effective value Cargo resolved out of your layered config files. cargo config get is still unstable under tracking issue #9301, so the command that would settle it, cargo +nightly -Zunstable-options config get registry.global-min-publish-age, needs a nightly toolchain. In CI, run the probe above against a throwaway crate rather than asserting on config text, the same discipline a green strict-allow-scripts gate needs before anyone trusts it.

Common pitfalls

Does cargo install respect the cooldown? No. The announcement says it "ignores the minimum publish age, for both the installed crate and its dependencies," and advises pinning with cargo install foo@1.2.3. On a runner this is the exposure that matters, because cargo install cargo-audit or cargo install cargo-deny fetches whatever was published minutes ago, inside the same job that is supposed to be auditing your dependencies. Pin the tool version and treat the pin as a dependency.

Will --locked save you there? It will not, and this one is marked breaking in the Cargo 1.100 changelog: "cargo-install: now uses the existing lockfile in the .crate tarball by default. --locked in cargo install becomes a no-op" (PR #17388). Tool dependency versions now come from the publisher's lockfile, with no age check layered on top.

Why is a two-hour-old version still in my build? Check Cargo.lock for it. The deny behaviour skips fresh versions during resolution and leaves locked ones alone, so adopting a cooldown changes what you resolve next, not what you are shipping today. Delete the lockfile in a scratch clone and re-resolve to see the policy applied from a clean slate.

A private registry prints nothing at all. Cargo emits no warning when pubtime is absent from an index entry. The curl in step 4 is the only check that separates "cooldown active" from "cooldown inert" on an internal index.

Units are explicit. "3 days" works; a unit-less value is not a documented form. months is accepted, which makes an over-wide window easy to type by accident and will hold back routine patch releases for weeks.

Wrap-up

You now have a three-day cooldown on third-party crates, a toolchain pinned to a version that honours the key, a zero window for internal registries, a per-command override for incident response, and a probe that distinguishes the active state from the inert one. What remains uncovered is binary tooling pulled by cargo install and anything already written into the lockfile, both of which need version pins rather than config.

RFC 3923 and the crates.io supply-chain hardening work both point at quarantine and suspicious-release detection arriving on top of this key, so widen the window where your release cadence tolerates it and re-measure:

cargo update --dry-run 2>&1 | grep -c 'as of min-publish-age'