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

Tlint Laravel Package

tightenco/tlint

Tlint is Tighten's opinionated command-line linter for Laravel projects. It checks PHP code against Laravel conventions and best practices, helping teams enforce consistent style, catch common issues early, and keep codebases clean and maintainable.

View on GitHub
Deep Wiki
Context7

Getting Started

TLint is a Laravel-convention linter and formatter. Treat it first as a targeted audit tool, not as a replacement for PHPStan, Larastan, Pint, or PHP_CodeSniffer.

Minimal adoption path:

  1. Install as a dev dependency:

    composer require tightenco/tlint --dev
    
  2. Run a read-only lint pass against a narrow, high-value directory first:

    ./vendor/bin/tlint lint app/Http/Controllers
    ./vendor/bin/tlint lint routes
    
  3. Pick one rule you care about and run it in isolation before enabling a preset:

    ./vendor/bin/tlint lint app --only=NoDump
    
  4. Add a tlint.json at the project root once you know which preset and paths you want. TLint v9+ uses a single tlint.json; older versions also used tformat.json, so avoid copying old blog-post configs into a current project.

  5. Wire a non-mutating lint command into CI after the local audit is clean:

    ./vendor/bin/tlint lint app routes tests
    

Where to look first:

  • The README’s preset, linter, formatter, and config sections.
  • ./vendor/bin/tlint command help in your installed version.
  • The bundled linters/formatters source and tests when a rule behaves unexpectedly.
  • The changelog before upgrading majors: v7 removed several redundant linters/formatters, and v9 changed configuration semantics.

Best first use case: run TLint against app/Http/Controllers, app/Models, routes, and Blade views to find Laravel-specific convention issues such as debug calls, facade imports, route path slashes, request helper opportunities, and Blade spacing. Then use formatters only on a clean branch for small, reviewable codemods.

Implementation Patterns

Local day-to-day linting

Use TLint on changed areas rather than always running the whole repository:

./vendor/bin/tlint lint app/Http/Controllers/UserController.php
./vendor/bin/tlint lint app/Models
./vendor/bin/tlint lint resources/views

Use --only for focused work:

./vendor/bin/tlint lint app --only=NoDump
./vendor/bin/tlint format app --only=FullyQualifiedFacades

This is especially useful when onboarding the team: start with low-risk rules, then expand to a preset.

Preset-based adoption

Configure a project preset once the initial audit is clean. A typical tlint.json will select a preset and scope paths:

{
    "preset": "laravel",
    "paths": ["app", "routes", "tests", "resources/views"]
}

Use the Tighten preset when you want Tighten’s house conventions; use Laravel when you want a broader Laravel-community baseline. Check the exact linters enabled by your installed version, because presets change between majors. v7 added FullyQualifiedFacades to both presets.

Formatters as controlled codemods

TLint’s formatters are useful for mechanical fixes, but treat them like refactoring tools:

  1. Start from a clean Git working tree.
  2. Run one formatter at a time on a narrow path.
  3. Review the diff.
  4. Commit the formatter change separately from functional work.

Example workflow:

git switch -c chore/tlint-formatting
./vendor/bin/tlint format app --only=UseAuthHelperOverFacade
git diff

Do not run formatters blindly across vendor, generated code, or large untouched areas unless you are prepared to review a large diff.

CI integration

Use linting in CI, not formatting:

./vendor/bin/tlint lint app routes tests

Keep formatting as a local or scheduled maintenance task. If you want CI annotations, v9.1+ added checkstyle reporting; check the installed version’s command help for the exact flag rather than assuming a generic --report syntax.

A practical Composer script:

{
    "scripts": {
        "lint:tlint": "tlint lint app routes tests",
        "format:tlint": "tlint format app routes tests"
    }
}

Then developers run:

composer lint:tlint

Pre-commit and changed-file workflows

TLint works well in a pre-commit hook if scoped to staged PHP/Blade files. Avoid running the full preset on every commit unless the repository is already clean; otherwise the hook becomes slow and noisy.

A reasonable pattern:

  • Pre-commit: lint only staged files, fail on violations.
  • PR CI: lint the configured project paths.
  • Scheduled job: run formatters on a branch for maintainers to review.

Coexistence with Pint and Duster

TLint is convention-focused and Laravel-specific. Pint handles general PHP style. Duster may wrap TLint alongside other tools. Avoid duplicate or conflicting auto-fixes by deciding which tool owns which concern:

  • Pint: PSR-style formatting, imports ordering, whitespace.
  • TLint: Laravel-specific conventions and Blade/route/controller idioms.
  • PHPStan/Larastan: type and static-analysis concerns.

Run formatters in a defined order and review diffs if both Pint and TLint touch the same files.

Custom linters and formatters

For team-specific conventions, TLint is extensible:

  • Add a custom linter by extending the base linter and registering it in config.
  • Add a custom formatter by extending BaseFormatter, using helpers such as replaceCodeLine and the code methods added in v8.
  • Use the shared visitor setup in the base linter rather than duplicating traversal setup.
  • Write fixture-based tests for custom rules, matching the package’s own testing approach.
  • Make config properties public where the base classes expect it; v8 changed config property visibility.

Keep custom rules few and well-documented. A custom TLint rule that nobody understands becomes permanent tech debt.

Gotchas and Tips

  • Pin the major version. TLint has had breaking changes across majors. v7 removed many linters/formatters, v8 added formatter APIs, and v9 changed configuration to a single tlint.json. Read the changelog before upgrading.

  • Do not treat TLint as a full static analyzer. It enforces Laravel conventions. It will not catch type errors, missing return types, or most runtime bugs.

  • Use --only for debugging. If a preset produces surprising output, isolate the rule:

    ./vendor/bin/tlint lint app --only=RuleName
    

    Since v6.2, --only works with linters/formatters even when they are not in the active preset.

  • Formatter output needs review. Formatters rewrite code. Run them on a clean branch, one rule at a time, and check for edge cases around comments, anonymous classes, dynamic calls, and mailable constructors. Several changelog entries are fixes for exactly these kinds of formatting bugs.

  • Update for known edge-case fixes. Examples from the changelog:

    • v9.6.1 fixed a crash on dynamic method calls.
    • v8.0.3 fixed anonymous-class and mailable-comment issues.
    • v9.4.0 ignored escaped Blade in SpacesAroundBladeRenderContent.
    • v6.2.2 fixed NoRequestAll to allow other request methods. If you hit a false positive, first check whether a newer patch release fixes it.
  • Blade rules need special care. Blade is not PHP AST in the same way as class files. Escaped Blade, directives, and render-content spacing are common false-positive areas. Scope Blade linting to resources/views and review formatter diffs closely.

  • Preset behavior is not universal. Laravel and Tighten presets differ, and their contents change. Do not assume a rule is active just because it exists in the package. Inspect the preset or run --only explicitly.

  • bootstrap directory behavior has changed. Recent releases adjusted whether TLint ignores or allows the bootstrap directory. If your CI suddenly lints or skips bootstrap files, check the installed version and changelog.

  • Older versions had Windows and EOL issues. v6.2.1 fixed DIRECTORY_SEPARATOR and PHP_EOL handling. If you are on an older version and see path or newline problems, upgrade rather than patching around it.

  • Config migration is a real upgrade task. Do not copy a tlint.json and tformat.json pair into a v9+ project. Consolidate into tlint.json and verify paths, preset, and rule configuration against the current README.

  • Keep the lint surface intentional. Linting vendor, storage, compiled assets, or generated files creates noise. Scope paths to application code, routes, tests, and views.

  • Use it as a teaching tool. TLint’s value is highest when it surfaces Laravel idioms during code review and onboarding. Pair violations with short team notes rather than expecting developers to infer the convention from a rule name alone.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource