Paulund
Subscribe

Laravel Pint: configuration, rules and CI checks

16 March 2026, 4 min read

From the archive. Versions and APIs may have moved on since I wrote this.

On this page
  1. Table of Contents
  2. What is Laravel Pint?
  3. Why Use Laravel Pint?
  4. Installation
  5. Configuration Explained
  6. Rule Categories
  7. Running Pint
  8. Best Practices
  9. Advanced Configuration
  10. Common Configuration Examples
  11. Troubleshooting
  12. Choosing a project configuration
  13. Related

Laravel Pint formats PHP code. Run ./vendor/bin/pint to apply fixes, or ./vendor/bin/pint --test to check formatting without changing files. Put project-specific presets and rules in a root-level pint.json file.

The Laravel Pint documentation covers the supported options. Pint formats PHP; it does not format Blade templates.

Table of Contents

  1. What is Laravel Pint?
  2. Why Use Laravel Pint?
  3. Installation
  4. Configuration Explained
  5. Rule Categories
  6. Running Pint
  7. Best Practices
  8. Advanced Configuration

What is Laravel Pint?

Laravel Pint is a zero-configuration PHP code style fixer for minimalists. It's built on top of PHP-CS-Fixer and provides:

  • Opinionated defaults - Works out of the box with Laravel conventions
  • Customisable rules - Extensive configuration options for team preferences
  • Parallel mode - Optional experimental processing with --parallel
  • Laravel integration - Seamless integration with Laravel projects

Pint ensures your code follows consistent formatting standards without requiring complex configuration.

Why Use Laravel Pint?

1. Zero Configuration

Works immediately with sensible Laravel defaults:

  • No setup required for basic Laravel projects
  • Follows Laravel's official coding standards
  • Uses Laravel style by default; select the psr12 preset for PSR-12

2. Consistent Code Style

Eliminates style debates and inconsistencies:

  • Uniform formatting across the entire codebase
  • Automatic fixing of common style issues
  • Consistent indentation, spacing, and structure

3. Developer Productivity

Reduces mental overhead and code review time:

  • Developers focus on logic, not formatting
  • Automated formatting in CI/CD pipelines
  • Fewer style-related code review comments

4. Team Collaboration

Ensures consistent code across team members:

  • Eliminates "style wars" between developers
  • Consistent code regardless of IDE or editor
  • Onboarding new team members with established standards

Installation

Laravel Projects

Laravel includes Pint as a dev dependency, so it's likely already in your project:

Terminal
# Check if Pint is installed
./vendor/bin/pint --version

# If not installed, add it manually
composer require laravel/pint --dev

For Non-Laravel Projects

Terminal
composer require laravel/pint --dev

Configuration Explained

Here's the configuration file (pint.json) with detailed explanations:

JSON
{
    "preset": "laravel",
    "notPath": ["tests/TestCase.php"],
    "rules": {
        "array_push": true,
        "backtick_to_shell_exec": true,
        "date_time_immutable": true,
        "declare_strict_types": true,
        "lowercase_keywords": true,
        "lowercase_static_reference": true,
        "final_class": true,
        "final_internal_class": true,
        "final_public_method_for_abstract_class": true,
        "fully_qualified_strict_types": true,
        "global_namespace_import": {
            "import_classes": true,
            "import_constants": true,
            "import_functions": true
        },
        "mb_str_functions": true,
        "modernize_types_casting": true,
        "new_with_parentheses": false,
        "no_superfluous_elseif": true,
        "no_useless_else": true,
        "no_multiple_statements_per_line": true,
        "ordered_class_elements": {
            "order": [
                "use_trait",
                "case",
                "constant",
                "constant_public",
                "constant_protected",
                "constant_private",
                "property_public",
                "property_protected",
                "property_private",
                "construct",
                "destruct",
                "magic",
                "phpunit",
                "method_abstract",
                "method_public_static",
                "method_public",
                "method_protected_static",
                "method_protected",
                "method_private_static",
                "method_private"
            ],
            "sort_algorithm": "none"
        },
        "ordered_interfaces": true,
        "ordered_traits": true,
        "protected_to_private": true,
        "self_accessor": true,
        "self_static_accessor": true,
        "strict_comparison": true,
        "visibility_required": true
    }
}

Configuration Breakdown

1. Preset Configuration

JSON
"preset": "laravel"
  • Purpose: Uses Laravel's official coding standards as the base
  • Alternatives: "psr12", "symfony", "per"
  • Effect: Applies Laravel-specific formatting rules

2. Path Exclusions

JSON
"notPath": ["tests/TestCase.php"]
  • Purpose: Excludes specific files from formatting
  • Common exclusions: Generated files, third-party code, legacy files
  • Example: ["bootstrap/cache/*", "storage/*", "vendor/*"]

3. Rule Categories

Modern PHP Features:

JSON
"declare_strict_types": true,
"modernize_types_casting": true,
"date_time_immutable": true
  • Enforces strict typing declarations
  • Modernises type casting syntax
  • Prefers DateTimeImmutable over DateTime

Code Quality Rules:

JSON
"final_class": true,
"final_internal_class": true,
"protected_to_private": true
  • Makes classes final when possible
  • Reduces visibility scope when appropriate
  • Improves encapsulation

Import Organisation:

JSON
"global_namespace_import": {
    "import_classes": true,
    "import_constants": true,
    "import_functions": true
}
  • Organises use statements
  • Imports global functions and constants
  • Reduces fully qualified name usage

Class Structure:

JSON
"ordered_class_elements": {
    "order": [
        "use_trait",
        "case",
        "constant",
        "property_public",
        "property_protected",
        "property_private",
        "construct",
        "destruct",
        "magic",
        "phpunit",
        "method_public",
        "method_protected",
        "method_private"
    ]
}
  • Enforces consistent class member ordering
  • Improves code readability
  • Standardises class structure

Rule Categories

1. Safety and Type Safety

JSON
{
    "declare_strict_types": true,
    "strict_comparison": true,
    "fully_qualified_strict_types": true
}

Before:

PHP
<?php

class Calculator
{
    public function add($a, $b)
    {
        if ($a == null) {
            return $b;
        }
        return $a + $b;
    }
}

After:

PHP
<?php

declare(strict_types=1);

class Calculator
{
    public function add(int $a, int $b): int
    {
        if ($a === null) {
            return $b;
        }
        return $a + $b;
    }
}

2. Code Organisation

JSON
{
    "ordered_class_elements": {
        "order": [
            "use_trait",
            "constant",
            "property_public",
            "property_protected",
            "property_private",
            "construct",
            "method_public",
            "method_protected",
            "method_private"
        ]
    }
}

Before:

PHP
class User
{
    public function getName(): string
    {
        return $this->name;
    }

    private string $name;

    public const STATUS_ACTIVE = 'active';

    public function __construct(string $name)
    {
        $this->name = $name;
    }
}

After:

PHP
class User
{
    public const STATUS_ACTIVE = 'active';

    private string $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function getName(): string
    {
        return $this->name;
    }
}

3. Modernisation Rules

JSON
{
    "modernize_types_casting": true,
    "mb_str_functions": true,
    "array_push": true
}

Before:

PHP
$string = (string) $value;
$length = strlen($text);
array_push($items, $newItem);

After:

PHP
$string = (string) $value;
$length = mb_strlen($text);
$items[] = $newItem;

4. Control Flow Improvements

JSON
{
    "no_superfluous_elseif": true,
    "no_useless_else": true,
    "no_multiple_statements_per_line": true
}

Before:

PHP
if ($condition1) {
    return 'A';
} elseif ($condition2) {
    return 'B';
} else {
    return 'C';
}

$x = 1; $y = 2;

After:

PHP
if ($condition1) {
    return 'A';
}

if ($condition2) {
    return 'B';
}

return 'C';

$x = 1;
$y = 2;

Running Pint

1. Basic Usage

Terminal
# Format all files
./vendor/bin/pint

# Format specific directory
./vendor/bin/pint app/

# Format specific file
./vendor/bin/pint app/Models/User.php

2. Preview Mode

Terminal
# See what would be changed without applying
./vendor/bin/pint --test

# Verbose output showing all changes
./vendor/bin/pint --test -v

3. Configuration Options

Terminal
# Use custom config file
./vendor/bin/pint --config=custom-pint.json

# Use specific preset
./vendor/bin/pint --preset=psr12

# Format only dirty files (git)
./vendor/bin/pint --dirty

4. CI/CD Integration

Terminal
# Test mode for CI (exits with error if formatting needed)
./vendor/bin/pint --test

# Combine with other tools
./vendor/bin/pint && ./vendor/bin/phpstan analyse

Best Practices

1. Pre-commit Hooks

Install a pre-commit hook to ensure code is formatted before commits:

Terminal
# Install pre-commit hook
echo '#!/bin/sh
./vendor/bin/pint --test
' > .git/hooks/pre-commit

chmod +x .git/hooks/pre-commit

2. IDE Integration

Configure your IDE to run Pint on save:

VS Code (.vscode/settings.json):

JSON
{
    "emeraldwalk.runonsave": {
        "commands": [
            {
                "match": "\\.php$",
                "cmd": "./vendor/bin/pint ${file}"
            }
        ]
    }
}

3. CI/CD Pipeline

YAML
# .github/workflows/pint.yml
name: Laravel Pint
on: [push, pull_request]

jobs:
    pint:
        runs-on: ubuntu-latest
        steps:
            - uses: actions/checkout@v4
            - uses: shivammathur/setup-php@v2
              with:
                  php-version: "8.3"
            - run: composer install --optimize-autoloader
            - run: ./vendor/bin/pint --test

4. Team Workflow

Terminal
# Developer workflow
git add .
./vendor/bin/pint
git add .
git commit -m "Your commit message"

# Or create alias
alias pint-commit="./vendor/bin/pint && git add . && git commit"

Advanced Configuration

Custom Preset

Create a custom preset for your organisation:

JSON
{
    "preset": "psr12",
    "rules": {
        "array_syntax": { "syntax": "short" },
        "binary_operator_spaces": {
            "default": "single_space"
        },
        "blank_line_after_namespace": true,
        "blank_line_after_opening_tag": true,
        "blank_line_before_statement": {
            "statements": ["return", "throw", "try"]
        },
        "class_definition": {
            "single_line": true,
            "single_item_single_line": true
        },
        "concat_space": { "spacing": "one" },
        "method_argument_space": {
            "on_multiline": "ensure_fully_multiline"
        },
        "no_unused_imports": true,
        "ordered_imports": {
            "sort_algorithm": "alpha"
        },
        "trailing_comma_in_multiline": {
            "elements": ["arrays", "arguments", "parameters"]
        }
    }
}

Environment-specific Configuration

JSON
{
    "preset": "laravel",
    "exclude": ["bootstrap/cache", "storage"],
    "notPath": ["tests/TestCase.php", "database/migrations"],
    "rules": {
        "declare_strict_types": true,
        "final_class": false,
        "php_unit_test_class_requires_covers": false
    }
}

Integration with Other Tools

Combined with Rector:

Terminal
#!/bin/bash
# Format and refactor script
./vendor/bin/rector process
./vendor/bin/pint
./vendor/bin/phpstan analyse

Package.json Scripts:

JSON
{
    "scripts": {
        "format": "./vendor/bin/pint",
        "format:test": "./vendor/bin/pint --test",
        "format:dirty": "./vendor/bin/pint --dirty"
    }
}

Common Configuration Examples

Laravel API Project

JSON
{
    "preset": "laravel",
    "rules": {
        "declare_strict_types": true,
        "final_class": true,
        "ordered_class_elements": {
            "order": [
                "use_trait",
                "constant",
                "property_public",
                "property_protected",
                "property_private",
                "construct",
                "method_public",
                "method_protected",
                "method_private"
            ]
        },
        "php_unit_test_class_requires_covers": false,
        "visibility_required": true
    }
}

Legacy Project Migration

JSON
{
    "preset": "psr12",
    "rules": {
        "declare_strict_types": false,
        "final_class": false,
        "modernize_types_casting": true,
        "no_superfluous_elseif": true,
        "no_useless_else": true,
        "protected_to_private": false,
        "strict_comparison": false
    }
}

Troubleshooting

Common Issues

  1. Memory Issues with Large Files
Terminal
php -d memory_limit=512M ./vendor/bin/pint
  1. Exclude Problematic Files
JSON
{
    "notPath": ["app/Legacy/*", "database/migrations/*"]
}
  1. Rule Conflicts
JSON
{
    "rules": {
        "final_class": false,
        "final_internal_class": false
    }
}

Choosing a project configuration

Laravel Pint does a good job of balancing zero-configuration simplicity with the customisation options teams actually need. For new projects, you can drop it in and run it immediately. For teams with specific conventions, pint.json gives you enough control to enforce them without writing a wall of configuration.

The key is to get it into your workflow early. Add it to your CI pipeline, set up a pre-commit hook, and let it handle the formatting decisions so your team can focus on the code that actually matters.

Getting started

  1. Check if Pint is already installed before reaching for Composer: ./vendor/bin/pint --version
  2. Run ./vendor/bin/pint to format your code
  3. Customise rules in pint.json as needed
  4. Add it to your CI/CD pipeline with --test mode
  5. Set up a pre-commit hook to catch issues before they reach the branch

Next in Laravel

16 March 2026Scheduled Tasks in Laravel