Open-Source Wikis

/

Laravel

/

How to contribute

/

Patterns and conventions

laravel/laravel

Patterns and conventions

This skeleton is small, but the patterns it sets up are the ones every Laravel application that scales out of it inherits. This page captures the conventions visible in the source so you don't accidentally fight them when adding your first features.

File layout

  • PSR-4 autoloading is configured in composer.json:
    • App\app/
    • Database\Factories\database/factories/
    • Database\Seeders\database/seeders/
    • Tests\tests/ (dev autoload)
  • No business logic in bootstrap/ or public/. Those directories are framework wiring and the web entry point. Application code lives under app/.
  • One config file per concern. config/ already has app.php, auth.php, cache.php, database.php, filesystems.php, logging.php, mail.php, queue.php, services.php, session.php. New cross-cutting features (e.g. third-party API integrations) follow the same shape — small files, mostly env() lookups, with comment headers explaining each section.

Coding style

  • Pint preset laravel governs PHP style (.styleci.yml):

    php:
      preset: laravel
      disabled:
        - no_unused_imports
      finder:
        not-name:
          - index.php

    index.php is excluded because it deliberately uses define() and a define('LARAVEL_START', microtime(true)); line that some Pint rules would touch. no_unused_imports is disabled to avoid noise from PHPDoc-only imports.

  • Tabs/spaces. .editorconfig enforces 4-space indentation in PHP, 2-space in YAML, and stripped trailing whitespace. The rule [*.md] opts Markdown out of trailing-whitespace stripping (so two-space line breaks survive).

  • End-of-line: LF for everything via .gitattributes (* text=auto eol=lf).

  • Imports: A v12.12.1 cleanup PR (see CHANGELOG.md and commit f1f2befa) standardized "unqualified names" in config files — i.e. import classes at the top of the file rather than referencing them with backslashes in the array. Follow that pattern when editing config/*.php.

PHP 8 attributes on models

app/Models/User.php uses Laravel's PHP 8 attributes for fillable/hidden:

#[Fillable(['name', 'email', 'password'])]
#[Hidden(['password', 'remember_token'])]
class User extends Authenticatable
{
    use HasFactory, Notifiable;

    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
        ];
    }
}

This is the modern replacement for protected $fillable / protected $hidden arrays. New models should follow the attribute pattern. The casts() method is the recommended form (over the older $casts property) and explicitly marks password as hashed so any value assigned is run through Hash::make() automatically.

Bootstrap-driven configuration

There is no App\Http\Kernel or App\Exceptions\Handler in this skeleton — those are gone in Laravel 11+. Anything you might have added to those classes goes inside the closures in bootstrap/app.php:

->withMiddleware(function (Middleware $middleware): void {
    // append/prepend middleware, group customization, alias registration, etc.
})
->withExceptions(function (Exceptions $exceptions): void {
    // ->reportable(...), ->renderable(...), ->dontReport(...) etc.
})

If you need a behaviour that used to live in the kernel, search the Laravel docs for the equivalent fluent method on Middleware or Exceptions.

Provider registration

Application providers are listed in bootstrap/providers.php:

return [
    AppServiceProvider::class,
];

Any new provider you create (e.g. App\Providers\AuthServiceProvider) must be appended here. Do not add framework or first-party package providers — those are auto-discovered from each package's composer.json.

Routing conventions

  • routes/web.php holds web routes (session + CSRF middleware applied automatically).
  • routes/console.php holds Artisan command definitions. The default inspire command lives there as a one-liner closure with ->purpose('Display an inspiring quote').
  • The skeleton ships no routes/api.php. If you need API routes, add the file and reference it from withRouting() in bootstrap/app.php.
  • Health checks are configured by passing a path string to withRouting(health: '/up'). Don't reinvent it.

Database conventions

  • Migrations are anonymous classes (return new class extends Migration) — the modern Laravel pattern. No class names to worry about.
  • Filenames follow Laravel 11+'s shortened format: 0001_01_01_000000_create_users_table.php (zero-prefixed, single-digit year segment). New migrations created via php artisan make:migration will pick a current timestamp instead.
  • Always pair up() with a down(). The three baseline migrations all do.
  • The users migration also creates password_reset_tokens and sessions in a single file. Group related schema changes when they belong to one feature.

Test conventions

  • Feature tests extend Tests\TestCase (tests/TestCase.php), which extends Illuminate\Foundation\Testing\TestCase. They get a booted application.
  • Unit tests extend PHPUnit\Framework\TestCase directly (no framework boot). The tests/Unit/ExampleTest.php is the reference.
  • Test method names use snake_case with a test_ prefix (PHPUnit also picks up @test annotations and Test suffix conventions, but test_* is what the example uses).
  • The phpunit.xml <source> block includes only app/, so coverage isn't polluted by config/, database/, etc. when you run with --coverage.

Composer scripts

composer.json defines named scripts that contributors are expected to use rather than chaining commands manually:

Script What it does
composer setup Full first-time setup (install deps, build assets, migrate)
composer dev Run server + queue + log tail + Vite in parallel
composer test Clear cached config, run PHPUnit

The post-autoload-dump and post-update-cmd scripts run framework hooks (package:discover, vendor:publish) automatically.

npm conventions

  • .npmrc enforces ignore-scripts=true (added 2026-04-01 in PR #6778) and audit=true (added 2026-04-15 in PR #6788). Both are security postures: don't run third-party postinstall scripts, and warn loudly about vulnerable transitive deps.
  • package.json declares "type": "module" and the project's only top-level scripts: build (vite build) and dev (vite).
  • All Node deps are devDependencies — there is nothing in dependencies.

Things you should not do here

  • Don't commit .env. It's listed in .gitignore.
  • Don't commit database/database.sqlite. database/.gitignore excludes the SQLite file.
  • Don't add a controller stub if you're going to delete it. This repo intentionally ships an empty app/Http/Controllers/ directory.
  • Don't broaden composer.json's minimum PHP. It's pinned at ^8.3. The CI matrix runs 8.3, 8.4, 8.5; a lowered floor would break compatibility tests.
  • Don't add packages you're not going to integrate. Recent commits (e.g. removing axios) move toward less, not more.

For testing/debug guidance see Testing and Debugging.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Patterns and conventions – Laravel wiki | Factory