Lockfiles are not optional
I commit composer.lock for applications. Production deploys should run composer install, not a casual composer update, unless I am deliberately reviewing upgrades. The lockfile is how I know which versions actually shipped.
# CI / production
composer install --no-dev --optimize-autoloader
# Local intentional upgrades (review the diff)
composer update vendor/package
git diff composer.lock
install vs update (say it out loud)
composer install— installs from the lockfile (reproducible)composer update— resolves anew and rewrites the lockfile
Mixing them up in deploy scripts is how “works in staging, different in prod” happens.
MFA everywhere publishers live
GitHub, Packagist, and npm publisher accounts need MFA. Account takeover is one of the most common ways malicious package versions ship—see recent npm phishing campaigns and PHP ecosystem incidents alike.
Prefer known maintainers for critical paths
Auth, payments, and encryption should not come from a random one-person package with no release discipline if a first-party or well-known alternative exists. That is a big reason I like Laravel’s official packages for common web needs.
Post-incident checklist
When something like the laravel-lang tag-rewrite incident happens:
- Identify whether you depend on the package (directly or transitively).
- Compare
composer.lockhashes / package refs to known-good releases. - Rebuild from a clean environment; avoid
composer updateblind. - Rotate CI secrets / deploy tokens if the pipeline could have been poisoned.
- Watch Packagist/GitHub advisories for the recovery path.
npm side note
This site still uses npm for Vite. Same rules: commit package-lock.json, prefer npm ci in CI, MFA on the npm account. The Laravel essay covers why I still default to Composer for backend critical path.
Troubleshooting and common mistakes
Most failures I see are configuration and process issues, not “the framework is broken.” Slow down: reproduce on a clean environment, read the exact error, and change one variable at a time.
- Confirm you are on the documented major version of the tool you are following.
- Prefer official docs over random outdated blog snippets when commands disagree.
- Keep lockfiles committed so teammates and CI install the same dependency graph.
- Separate “works on my machine” fixes (PATH, SDK licenses, local services) from application bugs.
What to do next
Implement the smallest vertical slice from this article on a throwaway branch, then promote the patterns into your real app. Guides that stay theoretical never catch the auth, env, and deploy footguns that actually burn time.
CI pattern I recommend
# GitHub Actions-style sketch
- uses: php-actions/composer@v6
with:
command: install
args: --no-dev --optimize-autoloader --prefer-dist
Cache Composer’s cache directory, but never skip the lockfile. Fail the build if composer.lock is missing on an application repo.
Private packages
For proprietary code, use private Satis/Packagist or VCS repositories with deploy tokens scoped as tightly as possible. Treat those tokens like production secrets.