Skip to content

Configuration reference

Put project settings under extra.lockrot in composer.json:

{
    "extra": {
        "lockrot": {
            "fail-on": "silent",
            "target-php": "8.4",
            "ignore": [
                { "package": "acme/legacy-bridge", "reason": "internal fork, tracked in ACME-123", "expires": "2027-01-01" }
            ]
        }
    }
}

CLI options win over environment variables, which win over composer.json.

The shape of extra.lockrot is validated against resources/lockrot-config.schema.json. Unknown keys are allowed, but the keys below must have the listed type — in particular, the four threshold keys must be JSON integers (3, not "3").

extra.lockrot keys

Key Default Meaning
fail-on none Exit 1 threshold: none, stale, old-promise, pinned, silent, abandoned
target-php config.platform.php, else the running PHP PHP version used for the S5 "old promise" check, e.g. "8.4"
format table table, json, github, sarif, gitlab or markdown; see ci.md
include-dev false Also check packages-dev (CLI: --dev)
install-time on on or off: print the install-time summary during composer require/update/install
install-time-strict false Apply fail-on at install time too, stopping the transaction instead of only reporting
install-time-budget 5 Integer seconds (1–120): the install-time pass's hard time budget
baseline lockrot-baseline.json Path to the baseline file, relative to composer.json or absolute
release-warn-years / release-high-years 3 / 5 Integer thresholds for "no stable release" (S2)
push-warn-years / push-high-years 3 / 5 Integer thresholds for "no repository push" (S4)
ignore [] Project allowlist, see below

Environment overrides

Variable Overrides
LOCKROT_DISABLE=1 (or true) Skips lockrot entirely, exits 0
LOCKROT_FAIL_ON fail-on
LOCKROT_TARGET_PHP target-php
LOCKROT_GITHUB_TOKEN / GITHUB_TOKEN GitHub token for repository-activity signals (S3/S4); Composer's github-oauth.github.com auth is used as a fallback if neither is set

CLI options

Option Meaning
--format=table\|json\|github\|sarif\|gitlab\|markdown Output format. table (the default) is a width-aware list grouped by priority, not a box table. The format changes the output only; the exit code is the same for all six. See ci.md
--fail-on=none\|abandoned\|silent\|pinned\|old-promise\|stale Exit-1 threshold for this run
--target-php=8.4 PHP version for the S5 check
--dev Include packages-dev. A development package is reported the same way a production one is, but it gets one priority step lower
--all Show every checked package, not only flagged ones. Adds a final not flagged group
--offline Never reach the network: lockrot sets COMPOSER_DISABLE_NETWORK=1 and rebuilds the configured repositories behind it (in plugin mode Composer has already built its own, network-enabled ones before any command runs), so repository metadata is served from Composer's own cache and GitHub activity from lockrot's cache. A package missing from the cache is reported as unavailable, not as absent from the repository
--strict-network Exit 1 (see ci.md) when a configured repository or GitHub could not be reached
--generate-baseline Write this run's findings to the baseline file and exit 0, whatever --fail-on says — --strict-network is the one exception
--baseline=<path> Baseline file to read (or, with --generate-baseline, to write); relative to composer.json or absolute. Wins over extra.lockrot.baseline. An empty --baseline= is a configuration error (exit 2), never a silent fall-back to the default file

-d <dir> points the standalone PHAR at a project; see phar.md.

Caching

Repository metadata is cached and revalidated by Composer itself, under Composer's own cache directory. lockrot adds no cache of its own for it, and there is no --refresh or cache-ttl knob to bypass or resize it.

GitHub repository-activity responses are cached separately under Composer's cache directory, in a lockrot/ subfolder, with a fixed 24-hour TTL. When Composer's cache is disabled (composer --no-cache), GitHub responses are kept in memory for the run only and nothing is written to disk. More in internals.md.

The allowlist

Packages that are finished by design — an interface package that will not release again, a polyfill that is deliberately frozen, a metapackage — are not dependency rot. lockrot ships a built-in allowlist at resources/finished-packages.json: psr/*, fig/*, symfony/polyfill-*, symfony/*-pack, ralouphie/getallheaders, and two pinned releases of paragonie/random_compat (9.99.99 and 9.99.100, which are intentionally empty). Packages of Composer type metapackage or symfony-pack count as finished automatically. An allowlist match is checked before any signal, so an allowlisted package reports finished whatever its signals say.

To silence one project dependency, add it to extra.lockrot.ignore. package and reason are mandatory; expires (YYYY-MM-DD) and version (pin the entry to one exact version) are optional. An entry whose expires date has passed is skipped, and the package falls back to its normal verdict:

{
    "extra": {
        "lockrot": {
            "ignore": [
                { "package": "acme/legacy-bridge", "version": "1.2.3", "reason": "internal fork, replacement tracked in ACME-123", "expires": "2027-01-01" }
            ]
        }
    }
}

To propose an addition to the built-in list — a genuinely finished package used widely enough to belong there — open a pull request against resources/finished-packages.json with the package pattern and a one-line reason, the same shape as the existing entries.

Testing hooks

Neither of these is part of the configuration contract.

Variable Effect
LOCKROT_TODAY (e.g. 2026-09-14) Fixes the reference date used for every "years ago" calculation
LOCKROT_RELEASE_URL Sends lockrot.phar self-update to this release document instead of GitHub's; for lockrot's own tests