Blog

PHP 8.5 and Laravel 13: modernise without manufacturing risk

Language and framework upgrades should buy clarity, supportability and safer change—not merely a newer version number.

Two senior engineers pairing over a laptop and a physical dependency map during a framework upgrade.

PHP 8.5 arrived in November 2025 with a built-in URI extension, the pipe operator, clone-with syntax, #[\NoDiscard] and persistent cURL share handles. Laravel 13 has continued to add framework-level improvements, including route metadata that survives route caching and can carry structured concerns such as permissions, feature flags or SEO information.

New capabilities are useful. A safe modernisation programme is still mostly about understanding the system you already have.

Define the value of the upgrade

"Current version" is not a sufficient outcome. Connect the work to something the organisation needs: supported security updates, simpler onboarding, reduced deployment friction, removal of abandoned packages, better observability or a platform feature that makes future delivery cheaper.

That goal decides the scope. If supportability is urgent, avoid combining the upgrade with a redesign and several behaviour changes. If the codebase has accumulated structural debt, reserve explicit time to simplify the small number of seams that make every upgrade difficult.

Map the real dependency surface

Composer describes packages, not the whole system. Inventory PHP extensions, queue workers, scheduled commands, build images, serverless runtimes, PDF tooling, image processing, deployment hooks and third-party SDKs. Find code that depends on framework internals or undocumented behaviour.

Then divide findings into three groups: incompatible, deprecated and merely unfamiliar. Fix incompatibilities first. Treat deprecation warnings as a managed backlog. Do not rewrite stable code solely to demonstrate every new language feature.

Upgrade through observable slices

A lower-risk sequence typically looks like this:

  • reproduce production in a supported local and continuous-integration environment;
  • update the runtime and framework constraints with the smallest viable package set;
  • run static analysis, tests and deprecation reporting;
  • exercise queues, schedules, mail, uploads and external callbacks;
  • deploy to a production-like environment with representative data;
  • release behind normal monitoring with an explicit rollback point.

For long-running workers, verify restart behaviour during deployment. For cached configuration and routes, test the same optimized commands used in production. A request test suite alone will miss much of the Laravel application lifecycle.

Adopt features where they remove ambiguity

PHP 8.5's URI objects can replace inconsistent URL parsing where correctness matters. #[\NoDiscard] can make ignored return values visible in APIs where omission is dangerous. Persistent cURL sharing may reduce repeated connection costs for integrations with the same hosts.

Laravel route metadata is valuable when it centralises a concern already attached to routes. It is less valuable if it becomes an untyped dumping ground. Define a small schema, document ownership and test the consumer.

The rule is simple: use a new feature when it makes intent clearer or operation safer. Familiar syntax with good tests is preferable to novelty distributed across the codebase.

Leave the system easier to upgrade again

Record the decisions, delete obsolete workarounds, update the base images and CI matrix, and turn the rehearsal checklist into a runbook. The strongest sign of a successful modernisation is not launch day. It is that the next upgrade becomes routine.

Sources

Bring us the whole project or the hardest part.

Tell us what the product or system needs to achieve, where the main risks are, and what has made it difficult.