Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Lean Package Validator Laravel Package

stolt/lean-package-validator

A CLI utility that validates a project or micro-package for leanness, ensuring common repository artefacts are excluded from release assets. It can also create, update, and reformat the leanness-enforcing export-ignore entries of a .gitattributes file.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is for the authoring side of Laravel packages, not for the Laravel app itself. Reach for it when you're building a package that ships as a Composer dist archive (which is the default install path for most consumers), and you want to make sure tests, CI configs, PHPStan configs, editor dotfiles, and Pint/PHPUnit caches don't end up inside that archive.

Minimal steps from your package root:

composer require --dev stolt/lean-package-validator
./vendor/bin/lean-package-validator validate

If validation fails, the fastest path to diagnosis is validate --diff, which renders a unified diff of your current .gitattributes versus the expected content. From there you either run create (no .gitattributes yet), update (one exists but is stale), or reformat (content is correct but layout is messy). All three support --dry-run where it makes sense — update and reformat do; use them first.

Where to look first:

  • The validate section of the README to understand classic vs. negated flavours — the tool validates both, and you should pick one for your repo.
  • src/Presets/PhpPreset.php to see exactly which paths are considered "common repository artefacts" in the default PHP preset. That's the source of truth for what it wants exported-ignored.
  • The example/.lpv file if you need to customise the glob pattern beyond the preset.

First real use case: a new Laravel package right before your first composer require yourvendor/yourpackage test from a separate app. Run create, commit, tag, then pull the dist tarball down manually to sanity-check. This is where the tool pays for itself — you catch a shipped tests/ directory or a stray phpunit.xml.dist before your first consumer sees it.

For one-off checks you can skip the dev dependency entirely:

cpx stolt/lean-package-validator validate

Implementation Patterns

Guard via a Composer script. This is the pattern the README itself recommends and the one that fits Laravel package workflow best, because it puts the check one command away for every contributor:

{
    "scripts": {
        "validate-gitattributes": "lean-package-validator validate"
    }
}

Then composer validate-gitattributes becomes the thing you put in composer test or a pre-push hook.

Gate CI on the archive, not just the file. validate checks the .gitattributes content; validate --validate-git-archive actually builds a temporary archive from HEAD and inspects it. For a release pipeline, the archive check is the meaningful one — it catches the case where your .gitattributes looks right but something else slipped in. A typical job:

- run: composer install --no-interaction
- run: ./vendor/bin/lean-package-validator validate --validate-git-archive --keep-license

Maintain, don't hand-edit. Once a .gitattributes is created, the update command is the workhorse. When you add a new tool (Pest, Rector, a new cache dir), you don't reason about what to add — you run update --dry-run, eyeball the diff, then run it for real. It preserves non-export-ignore rules and appends new export-ignores below them. reformat is for cosmetic drift: --sort-alphabetically, --sort-from-directories-to-files, --group.

Use .lpv for anything non-vanilla. If you're on the default PHP preset you don't need it. But if your package has unusual paths, generate a .lpv with init and commit it — validate picks it up automatically. When the upstream PHP preset grows new entries in a later release, refresh adds the missing ones while leaving your manual entries alone. That's the upgrade path: bump the package, run refresh --dry-run, commit, done.

Enforce style consistently or not at all. --enforce-strict-order and --enforce-alignment are opt-in for a reason. If you enable them, make sure everyone's regenerating the file with the tool rather than editing by hand, otherwise every stray update by a teammate with a different sort preference will fail CI. For most teams the non-strict default (order-insensitive) is the right call, with reformat used occasionally to tidy up.

Preset switching for polyglot repos. If you have a Laravel package with a bundled JS build or Rust extension, --preset JavaScript / --preset Rust changes the glob pattern set. Note this is per-invocation unless you carry a .lpv — the preset flag on validate doesn't mutate a .lpv.

Gotchas and Tips

  • .gitattributes affects git archive and Composer's dist archives, not the working tree. A contributor who git clones and installs from source never sees this. It matters only for consumers installing from a dist tarball — which is most of them, so don't skip it.
  • --validate-git-archive operates on HEAD, not your working directory. Uncommitted changes are invisible to it. In CI that's fine; locally it means you must commit before the check is meaningful, and a green run against an old commit is a false sense of security.
  • --keep-license combined with --validate-git-archive makes a license file mandatory — if you don't have one, validation fails rather than passing leniently. Same idea with --keep-readme. Pick your flags deliberately; adding --keep-license to satisfy a legal obligation and then forgetting it in one job is a subtle way to get inconsistent CI.
  • Stale entries are silent by default. If you delete phpstan.neon.dist but leave its export-ignore line, plain validate still passes. Add --report-stale-export-ignores (and ideally --diff) to surface them.
  • create --force will overwrite an existing .gitattributes. If that file holds non-export-ignore rules (line-ending normalisation, *.php text eol=lf, binary markers), you lose them. Prefer update whenever the file exists.
  • update appends below existing rules and respects --omit-header. If a teammate strips the header in their branch, update without --omit-header will reintroduce it and produce a noisy diff.
  • Order comparison is non-strict by default. That means two contributors with different sort preferences both pass validation locally but produce different files — you'll see churn in .gitattributes diffs. Decide the policy once.
  • --enforce-alignment is brittle against mixed editor setups (trailing whitespace, tab/space). It's great for a solo repo, annoying for a distributed team. If you enable it, wire reformat --align-export-ignores-style regeneration into the same CI job that validates.
  • --glob-pattern and --glob-pattern-file expect the brace grouping to have more than one pattern. A single-element {foo} will not behave how you expect. Use {.lpv} for anything complex rather than long inline flags.
  • --stdin-input only does a strict comparison — it doesn't apply presets, alignment, or stale reporting. It's fine for a quick pipe check but don't use it as your CI gate.
  • The tree --src and tree --dist-package commands are inspection only. They're the fastest way to eyeball what would ship before you tag, but the tool explicitly says they're not for validation — don't script against their output.
  • Global installs need your Composer bin-dir on $PATH; the README's alias recipe (alias lpv='~/.config/composer/vendor/bin/lean-package-validator $@') is worth setting up as the name is long enough that you won't type it otherwise, which is how .gitattributes files go stale in the first place.
  • composer.json must never be export-ignored — the default presets correctly keep it in. If you ever hand-edit and add it, composer require from dist breaks. The validate --validate-git-archive path catches this; plain content validation against a custom glob might not.
  • Extension point worth knowing: the three bundled AI skills (resources/boost/skills) document validate/update/create flows in agent-friendly form. If you're using an agent to maintain .gitattributes, point it at those rather than rederiving the workflow.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table