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/orpublic/. Those directories are framework wiring and the web entry point. Application code lives underapp/. - One config file per concern.
config/already hasapp.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, mostlyenv()lookups, with comment headers explaining each section.
Coding style
Pint preset
laravelgoverns PHP style (.styleci.yml):php: preset: laravel disabled: - no_unused_imports finder: not-name: - index.phpindex.phpis excluded because it deliberately usesdefine()and adefine('LARAVEL_START', microtime(true));line that some Pint rules would touch.no_unused_importsis disabled to avoid noise from PHPDoc-only imports.Tabs/spaces.
.editorconfigenforces 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.mdand commitf1f2befa) 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 editingconfig/*.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.phpholds web routes (session + CSRF middleware applied automatically).routes/console.phpholds Artisan command definitions. The defaultinspirecommand 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 fromwithRouting()inbootstrap/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 viaphp artisan make:migrationwill pick a current timestamp instead. - Always pair
up()with adown(). The three baseline migrations all do. - The
usersmigration also createspassword_reset_tokensandsessionsin a single file. Group related schema changes when they belong to one feature.
Test conventions
- Feature tests extend
Tests\TestCase(tests/TestCase.php), which extendsIlluminate\Foundation\Testing\TestCase. They get a booted application. - Unit tests extend
PHPUnit\Framework\TestCasedirectly (no framework boot). Thetests/Unit/ExampleTest.phpis the reference. - Test method names use
snake_casewith atest_prefix (PHPUnit also picks up@testannotations andTestsuffix conventions, buttest_*is what the example uses). - The phpunit.xml
<source>block includes onlyapp/, so coverage isn't polluted byconfig/,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
.npmrcenforcesignore-scripts=true(added 2026-04-01 in PR #6778) andaudit=true(added 2026-04-15 in PR #6788). Both are security postures: don't run third-partypostinstallscripts, and warn loudly about vulnerable transitive deps.package.jsondeclares"type": "module"and the project's only top-level scripts:build(vite build) anddev(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/.gitignoreexcludes 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.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.