Every Laravel project I review shares a similar origin story: a tight, well-organised codebase that slowly rots into god controllers, fat models, and N+1 query storms within a year. The framework rarely causes the decay — we do, by treating conventions as optional. The practices below are the ones that separate applications that remain pleasant to extend in 2026 from those that quietly become the company's biggest technical debt.

Keep Controllers Thin with Actions and DTOs

The single highest-leverage change is moving business logic out of controllers. A controller should read a validated request, dispatch one action, and return a response. Actions are invokable classes that encapsulate a single use case; DTOs (data transfer objects) carry typed input between the HTTP layer and the domain. Laravel's constructor promotion and typed properties make this clean without ceremony.

When you add a third route calling the same logic, the action is waiting for you. When a test needs to exercise a business rule, it targets the action, not the HTTP stack. This is where Form Requests earn their keep too: put validation and authorization rules in one class and reuse it across web and API — never duplicate a rule that exists in two files.

Configuration Discipline: env() Only in Config Files

env() called anywhere outside config/ is a latent bug. Cached configuration (php artisan config:cache) freezes environment values at build time, so runtime env() calls silently return null in production. Enforce a convention: every service variable lives in a config file, is registered in a config provider, and is read through config('...') everywhere else. Add a CI check that greps for env() outside config/ and static analysis that flags unvalidated config reads.

Cache and Queue as First-Class Concerns

Octane turns Laravel into a long-lived worker, so anything that leaks between requests — mutable static properties, facades holding per-request state, unclosed connections — becomes a production incident. Adopt it early and run your integration test suite against Octane in CI. For queues, treat jobs as the system's spine: use Redis for both cache and queues, set explicit timeout and attempts on every job, and make jobs idempotent so a retry never double-charges a customer or delivers a duplicate email. Write a consumer that can safely replay any job at least once.

Query Discipline: Eager Loading and Explicit Columns

Most performance incidents are database incidents in disguise, and N+1 queries are the classic culprit. Preload relationships, use scopes for filterable columns, and select only what you render — select('id', 'title') on index pages changes page weight noticeably. Run the query log in staging and watch the query count per screen; anything above twenty deserves attention, and smart pagination plus chunking keeps memory flat on long lists.

First-Party Packages: Less Glue, More Focus

Laravel's 2026 line-up — Folio for file-based routing, Livewire for reactive interfaces, Socialite for OAuth, Prompts for CLI — removes the plumbing that used to invite bugs. Prefer first-party tools until a third-party library clearly wins on capability. Pin every dependency in composer.lock, schedule Dependabot updates through CI, and let minor upgrades land continuously so majors are boring when they arrive.

Testing Rails: Speed and Determinism

A test suite nobody runs is decoration, and speed is the retention strategy. Use a dedicated test database with RefreshDatabase, run tests in parallel, and favour factories over global fixtures so each test owns its data. Treat tests as documentation: a failing test should tell you which business rule broke, not where the framework tripped. Combine that with a strict static-analysis floor and the codebase stops surprising you.

A Minimum Bar for Every Merge

  • Static analysis (PHPStan at level 8+) and Laravel Pint passing in CI.
  • No env() outside config files, enforced by a grep check.
  • Every new endpoint has a feature test; every business rule has a unit test.
  • Query counts stay flat after schema changes — verify with the query log.
  • Cache keys and queue job contracts are documented and versioned.

None of this requires heroic effort; it requires consistency. If your team needs a baseline Laravel architecture, migrations, or a review of an existing codebase, Smart Logic's Laravel and full-stack development team can audit your code, wire up CI with these checks, and hand you a roadmap that turns maintenance into iteration. Contact us to schedule a code review before your next feature sprint.