Running a Laravel app in production is more than just pushing code to a server. The decisions you make today affect scalability, security, and the cost of future changes. The following checklist is built on first‑principles and real‑world experience, so you can evaluate each item quickly and act on the ones that matter most for your team.
1. Code Quality and Architecture
- Prefer Service‑Container Bindings Over Facades
Facades are convenient but hide the underlying dependencies. Register concrete classes in
AppServiceProviderand inject them via the constructor. This makes unit testing trivial.
// App\Providers\AppServiceProvider.php
public function register()
{
$this->app->bind(
App\Contracts\PaymentGateway::class,
App\Services\StripeGateway::class
);
}
// In a controller
use App\Contracts\PaymentGateway;
class OrderController extends Controller
{
private $gateway;
public function __construct(PaymentGateway $gateway)
{
$this->gateway = $gateway;
}
public function store(Request $request)
{
$this->gateway->charge($request->amount);
// ...
}
}
-
Domain‑Driven Folder Structure Keep the default
app/Models,app/Http, etc., but add aapp/Domainlayer for business logic. Controllers become thin request‑handling shells, while services encapsulate use‑cases. -
Avoid Fat Controllers If a controller method exceeds 30 lines, extract the logic into a service class or an Action (single‑purpose invokable class). This improves readability and testability.
-
Write Unit Tests First Aim for 70‑80 % coverage on core services. Use Laravel’s built‑in testing helpers; they spin up an in‑memory SQLite database, keeping the feedback loop fast.
2. Configuration and Environment Management
-
Never Store Secrets in
.envon the Server Use your hosting platform’s secret manager (e.g., Laravel Vapor, AWS Parameter Store, or Docker secrets). In your code, referenceconfig('services.stripe.key')rather thanenv('STRIPE_KEY')directly. -
Cache Config and Routes Run
php artisan config:cacheandphp artisan route:cacheduring deployment. This compiles the configuration files and route list into a single PHP file, reducing bootstrap time. -
Separate Config for Each Environment Keep
config/*.phpenvironment‑agnostic and place environment‑specific values in the secret store. This prevents accidental leakage of dev settings into prod. -
Version‑Control Only the Skeleton
.env.exampleInclude placeholders for every key your app needs, so new developers can spin up a local copy without guessing.
3. Performance Optimizations
- Leverage Query Caching Frequently accessed read‑only data (e.g., product categories) should be cached. Laravel’s cache tags let you invalidate related keys in a single call.
$categories = Cache::tags(['catalog'])->remember('categories', now()->addHours(2), function () {
return Category::all();
});
-
Use Eager Loading Wisely N+1 queries are a common source of latency. Use
with()on relationships you know you’ll need, but avoid loading massive collections you never touch. -
Queue Time‑Consuming Work Anything that can be deferred—emails, image processing, PDF generation—should be pushed to a queue. Laravel Horizon provides a clear dashboard for Redis‑backed queues.
-
Optimize Blade Rendering Turn on Blade component caching with
Blade::componentCachePath()if you generate many dynamic components. Also, avoid heavy logic inside templates; move it to view composers or service classes. -
Static Asset Pipeline Compile CSS/JS with Laravel Mix or Vite, enable versioning (
mix.version()), and serve the compiled assets via a CDN. This reduces the time‑to‑first‑byte for end users.
4. Security Hardening
-
Enforce HTTPS Everywhere In
AppServiceProvider::boot(), callURL::forceScheme('https');for non‑local environments. Also enable HSTS headers via middleware. -
Rate Limit Critical Endpoints Use Laravel’s built‑in
ThrottleRequestsmiddleware to protect login, password reset, and API token issuance routes.
Route::post('login', [AuthController::class, 'login'])
->middleware('throttle:5,1'); // 5 attempts per minute
-
Validate All Input Rigorously Never rely on client‑side validation alone. Use Form Request classes with explicit rules, and consider custom validators for business‑specific constraints.
-
Sanitize Output When rendering user‑generated HTML, use a library like
HTMLPurifierto strip unsafe tags. Laravel’se()helper escapes output by default, but for rich text you need an extra layer. -
Keep Dependencies Updated Run
composer outdated --directweekly and apply security patches promptly. Automate this with Dependabot or Renovate to avoid manual drift.
5. Observability and Incident Response
-
Centralized Logging Ship logs to a log aggregation service (e.g., Papertrail, Loggly, or ELK). In
config/logging.php, configure adailychannel for local fallback and astackthat includes the remote driver. -
Health Checks Expose a
/healthendpoint that returns 200 OK only when the database, cache, and queue workers are responsive. Use Laravel’sRoute::viewwith a simple closure that runs quick checks.
Route::get('health', function () {
try {
DB::connection()->getPdo();
Cache::has('test');
return response()->json(['status' => 'ok']);
} catch (\Exception $e) {
return response()->json(['status' => 'error'], 500);
}
});
-
Metrics Collection Instrument key business events (order placed, user sign‑up) with Prometheus client libraries or Laravel’s built‑in
Event::listento push counters to a monitoring system. -
Automated Deployments with Rollback Use a CI/CD pipeline that runs the full test suite, builds assets, and performs a zero‑downtime deployment (e.g., via Laravel Envoy or GitHub Actions with
php artisan down/up). Keep the previous release artifact so you can rollback instantly if health checks fail. -
Post‑mortem Process After any outage, document the timeline, root cause, and mitigation steps in a shared Confluence page. This habit turns incidents into learning opportunities and reduces future MTTR.
Quick Takeaways
- Inject, don’t Facade – improves testability.
- Cache config, routes, and query results – cuts boot time.
- Queue every non‑critical task – frees request threads.
- Rate‑limit and enforce HTTPS – basic but essential security.
- Add health checks and centralized logs – detect problems before users do.
Implementing even a subset of these practices will raise the reliability bar of your Laravel application and give your team confidence to ship faster.
- Laravel
- Best Practices
- Php
- Devops
- Production