You hired a vendor to build your Laravel app. The demo runs, the screens load, and the invoice is on its way. What is under the hood, though, is a separate question, and one most teams only ask after something breaks.
That trust gap is why we put this guide together. The list below is the same one our reviewers use when auditing Laravel codebases, and it mirrors the framework behind every Laravel code review we run for clients. Many teams inherit a Laravel codebase rather than question one, so run the steps below before your next handoff or release and you will catch what costs the most to fix later.
Laravel Coding Standards (PSR-12)
Code that ignores conventions is hard to read, hard to onboard new developers into, and a magnet for bugs. PSR-12 is the PHP-FIG standard the Laravel ecosystem follows by default, and a review starts here because every later check builds on a codebase you can read. We treat this layer as table stakes, not nice-to-have.
What We Check in Formatting and Naming
Three patterns we flag first when opening a fresh codebase:
- Mixed indentation, lines longer than 120 characters, no type hints anywhere.
- Models named in plural (Users instead of User), controllers without the Controller suffix.
- snake_case columns sitting next to camelCase ones in the same migration.
A clean reviewer pass expects 4-space indentation, PascalCase models, camelCase methods, snake_case columns, plural table names, and type hints on every parameter and return value. PHPDoc blocks should explain the why on public methods.
Pint and Larastan in CI
Tools enforce Laravel coding standards so reviewers can focus on logic. Pint is the official Laravel formatter, and Larastan adds Laravel-aware static analysis on top of PHPStan. Both should run in continuous integration, because conventions only stick when the pipeline blocks merges that break them.
A minimal CI step looks like this:
vendor/bin/pint --test
vendor/bin/phpstan analyse --memory-limit=2G
When either command fails, the pull request stops. That single rule prevents most style drift across teams of any size.
Clean Code and Architecture
Laravel makes shipping fast, which is both its strength and its trap. Many codebases we audit delivered a working MVP with logic spread across controllers, models, and Blade templates, and the cleanup later costs more than the original build. Laravel clean code is the difference between a codebase you can extend in year two and one you have to rewrite.
Thin Controllers, Service Classes, and Action Classes
A controller’s job is HTTP, nothing more. When we see methods longer than 30 lines we know business logic has leaked in, and the fix is a service class or a single-purpose action class.
Bad:
public function store(Request $request)
{
$data = $request->validate([
'email' => 'required|email',
'plan' => 'required|in:basic,pro',
]);
$user = User::create($data);
Mail::to($user->email)->send(new WelcomeMail($user));
Subscription::create([
'user_id' => $user->id,
'plan' => $data['plan'],
]);
return redirect()->route('dashboard');
}
Better:
public function store(RegisterRequest $request, RegisterUser $action)
{
$action->execute($request->validated());
return redirect()->route('dashboard');
}
The controller now reads in one breath. The action class is testable on its own and reusable from a console command or queued job, which is what makes refactors safe.
Form Requests and Policies
Inline validation and inline authorization are two of the most common shortcuts we untangle. Validation rules belong in Form Request classes, and authorization belongs in Policies registered against the model. Both moves shrink controllers and put the rules where developers expect to find them, which speeds up onboarding and reduces bugs introduced by the next person who touches the file.
If you keep spotting controllers with 200 lines of mixed responsibilities, the issue is deeper than refactoring, and it might be time to bring in a software architecture consultant before the cleanup turns into a rewrite.
Eloquent and Database Queries
Eloquent is elegant and dangerous in equal measure. The ORM hides the cost of a query, and a careless foreach fires off hundreds of database calls under the surface. Performance audits often start in this layer.
N+1 Queries and Eager Loading
The N+1 query is the most common Laravel performance bug we find. The pattern looks innocent on screen:
$posts = Post::all();
foreach ($posts as $post) {
echo $post->author->name; // one extra query per post
}
The fix is with():
$posts = Post::with('author')->get();
foreach ($posts as $post) {
echo $post->author->name; // no extra queries
}
Add Model::preventLazyLoading() in your AppServiceProvider for non-production environments and Laravel will throw an exception the moment lazy loading happens. The bug surfaces in your test suite rather than under production load.
Indexes, Mass Assignment, and Migrations
Three database-layer checks we run on every audit:
- Foreign keys and frequently filtered columns have indexes.
- Models declare $fillable or $guarded deliberately, so a rogue input cannot overwrite admin-only fields.
- Migrations have working down() methods, so rollbacks do not corrupt production data.
The third one matters more than most teams realise. A migration without a rollback is a one-way door, and that door always opens at the worst possible time.
Laravel Security Best Practices
Security is where vendor handoffs fail most painfully. According to the IBM Cost of a Data Breach Report 2025, the global average breach now costs USD 4.44 million, and USD 10.22 million in the United States. A code review is the cheapest moment to find the gaps that lead to those numbers.
Environment, CSRF, XSS, and File Uploads
These are the most-missed Laravel security best practices in our audits. A quick verification list:
- APP_DEBUG=false and APP_ENV=production in production environments.
- .env excluded from version control and returning 403 over HTTP.
- CSRF middleware enabled on every state-changing route.
- Blade {{ }} used for output, with {!! !!} only after explicit sanitization.
- File uploads validated for MIME type, size, and extension, then stored outside the public directory.
The OWASP Top 10 covers the broader categories these checks defend against. Mapping your audit findings to OWASP categories gives the report a structure your security team will recognise.
Authentication, Rate Limiting, and Dependency Audits
Passwords should hash with bcrypt or Argon2, never MD5 or SHA1. APIs should use Laravel Sanctum or Passport, with the throttle middleware applied to login and password reset endpoints to stop brute force. The composer audit command should run in CI on every build, so a freshly published vulnerability in a dependency does not stay unnoticed for weeks.
A single outdated package can undo every other check on this list. That is why a review without a dependency audit is incomplete.
Laravel Performance Optimization
Performance issues rarely arrive as a single bug. They build up across several layers, and a review surfaces the layers that are silently expensive. Laravel performance optimization during an audit is diagnosis, not implementation, so the report tells you where the cost lives and why.
A few things we verify on every project:
- Route, config, view, and event caches are warm in production (php artisan route:cache, config:cache, view:cache, event:cache).
- Heavy work (email, exports, third-party API calls, image processing) is dispatched to queues with a real driver like Redis, not synchronous.
- Every list endpoint is paginated, with no Model::all() on a table that grows.
- A cache layer sits in front of expensive reads, with sensible time-to-live values.
- OPcache is enabled at the PHP level.
- Telescope or Laravel Debugbar findings from staging have been reviewed.
A common pattern in MVPs is to deploy without any of the above and discover the cost when traffic doubles after a launch. The trade-off is documented in our analysis of the hidden costs that show up later.
Tests and Reliability
A Laravel app without tests is a Laravel app one refactor away from production downtime. The codebase does not need 100% coverage to be safe, but the critical paths absolutely do. What we look for is a Pest or PHPUnit suite that runs green in continuous integration, feature tests on every revenue-touching flow (authentication, payment, core CRUD), factories defined for the main models so test data is one line of code, the RefreshDatabase trait on every test that touches the database, and external APIs mocked rather than hit during the suite.
When the suite is missing or red, the right starting move is characterisation tests around current behaviour, followed by refactoring. Coverage built around a frozen contract is the only kind you can trust later, and teams that skip this step usually pay for it twice, first in confidence and then in incident reports.
Dependencies and Tooling
The dependency graph is often the most-overlooked part of a Laravel application. Outdated frameworks and abandoned packages account for a large share of the vulnerabilities and incompatibilities we see, and running on supported versions correlates strongly with team velocity in every developer survey of the last few years.
The checklist here is short but it bites if you skip it. Laravel should be on a supported release (Laravel 12 has security support through February 24, 2027). PHP should be on 8.3 or 8.4, not earlier. The composer.lock file should be committed and identical across developer machines, CI, and production. There should be no packages flagged as abandoned by composer audit. Pint, Larastan, and Pest should run in CI on every push, with Rector added if you want automated upgrade refactors across PHP and Laravel versions.
What Our Laravel Code Review Checklist Uncovers in Real Audits
Numbers tell the story better than promises. Across the last cycle of audits in our team, our reviewers logged 82 security vulnerabilities across 15 Laravel and PHP projects, 27 cases of copy-paste programming, and 23 cases of dependency conflicts severe enough to block deployments. Most of those issues sat in code that the original team thought was production-ready.
Top 5 Laravel Red Flags
The patterns repeat across audits, and these five issues come up most often:
- Fat controllers with validation, business logic, and side effects in a single method.
- N+1 queries on dashboard endpoints that only show up under real load.
- .env leaked through APP_DEBUG=true on a staging URL exposed to the internet.
- No rate limiting on login or password reset, leaving the door open to brute force.
- AI-generated code that runs on the happy path and quietly skips Form Requests, Policies, and tests.
When an MVP is delivered with several of these, the cleanest path forward is a structured review followed by ongoing Laravel maintenance rather than another full rewrite. For teams ready to scale the same stack into a paid product, our Laravel development services pick up where the review report ends.
Final Thoughts
A Laravel code review checklist is not a substitute for senior engineering judgement, but it is the cheapest way to make that judgement repeatable. Following established Laravel best practices during every review, every release, and every vendor handoff is what separates an app you can scale from one you will have to rebuild. The work pays for itself the first time you avoid a Friday-night rollback or a Monday-morning security disclosure.
If you would rather have a second pair of eyes on the codebase, or simply do not have the bandwidth to run the audit internally, contact us and we will scope a review around your stack.
See how Redwerk audited a backend API and increased its maintainability by 80% with a structured code review.