What a PHP to Laravel migration actually involves
A PHP to Laravel migration replaces the structure of your application, not the language. The code stays PHP; what changes is that routing, database access, authentication, validation and templates move from hand-written scripts into the conventions Laravel provides.
Most legacy core-PHP apps we see follow a familiar shape: one PHP file per screen, database queries written inline, a config.php with credentials, sessions handled by hand, and HTML mixed with logic. They work, often for a decade, which is exactly why owners hesitate to touch them.
Laravel gives each of those concerns a home. URLs are declared in route files. Database tables are represented by Eloquent models. Form input passes through validation rules before any code touches it. Templates live in Blade views that escape output by default. Background jobs, scheduled tasks and email each have their own framework feature.
The goal is not a prettier codebase for its own sake. It is an application that a new developer can understand in days rather than months, that passes a security review, and that can grow without every change breaking something unrelated.
Is it worth migrating from core PHP to Laravel?
It is worth it when the app is central to the business and likely to live for years more. It is not worth it for a tool you plan to retire next year.
Three pressures usually force the question. First, PHP itself: php.net explains that each release branch gets two years of active support and two further years of security fixes, and branches up to PHP 8.1 are already end of life. Old core-PHP code written for PHP 5 or 7 often breaks on current versions, so staying put means running unsupported software. Second, security: hand-rolled login and query code is where most legacy PHP holes sit. Third, people: developers are easier to find, and faster to onboard, for a Laravel codebase than for a unique home-grown structure.
Migrate when
Staff or customers use the app daily, you keep adding features, the code will not run on a supported PHP version, or a security review has flagged it.
Upgrade PHP only when
The app is stable, rarely changed and due for replacement within a year or two; a careful PHP version upgrade buys time for less money.
Replace when
An off-the-shelf product now does what your custom app does. Our off-the-shelf vs custom software guide helps you judge that.
Compare the two routes in more depth on off-the-shelf vs custom software.
Incremental PHP to Laravel migration vs full rewrite
For any app your business depends on, incremental migration is safer than a full rewrite. The old application keeps running while Laravel takes over one piece at a time, so there is never a single day when everything has to work at once.
The idea has a name: the Strangler Fig pattern. Microsoft's Azure Architecture Center describes it as incrementally replacing specific pieces of functionality with new services until the old system can be decommissioned, with a façade routing each request to either the old or the new code. In a PHP to Laravel migration, Laravel itself is that façade.
The same guidance lists when the pattern is not suitable: when the system is small and replacing it whole is simple, or when you cannot change the old source code. We agree. A 15-screen internal tool with no daily users is often faster to rewrite cleanly. A 200-screen order system with staff logged in all day is not.
- Choose incremental when downtime is expensive and the app has many modules
- Choose a rewrite when the app is small, rarely used, or needs a completely new workflow
- Either way, write tests for current behaviour before replacing anything
How Laravel sits in front of the old PHP code
On day one, Laravel becomes the entry point for every request, and anything it does not yet handle is passed straight to the legacy script. Users see the same screens; nothing looks different.
Technically, the web server sends all traffic to Laravel's front controller. Routes for migrated modules go to new controllers. A catch-all fallback route hands every other URL to a small bridge that loads the matching old PHP file, with the same request data it always received. As modules move, their routes are added and the fallback handles less and less.
This approach has practical benefits. Logging, error reporting and security middleware apply to the whole application immediately, including the old parts. We can add rate limiting to the login page or force HTTPS everywhere in the first week, long before most screens have been rewritten.
The bridge is temporary scaffolding. When the last legacy file is migrated, the fallback route and the old folder are deleted, and the application is simply Laravel.
Can Laravel use my existing PHP database?
Yes. Laravel works with your existing MySQL, MariaDB or PostgreSQL tables as they are, so a PHP to Laravel migration does not require a new database or a risky data transfer.
Eloquent models can be pointed at existing table names, primary keys with unusual names, and tables that have no created and updated timestamp columns. Where the old schema lacks foreign keys or uses inconsistent column types, we leave it alone at first, map it faithfully, and fix it later with Laravel migrations once both old and new code agree on the structure.
The one rule during the overlap period: the database is shared, so any schema change must keep the old scripts working too. We add columns rather than rename them, write data in formats the old code understands, and only drop legacy columns after every screen that used them has moved.
Before touching anything, we take a full backup, restore it to a staging server and run the whole migration there first. Your live data is never the test bed.
- Map existing tables to models without renaming them
- Record the current schema as a baseline in version control
- Add indexes and constraints gradually, after checking the data obeys them
- Keep legacy-readable formats until the last old screen is gone
Moving authentication and old passwords to Laravel
Authentication should move first, because it is where old PHP apps are weakest and because every later module depends on it. Done well, users notice nothing except perhaps a faster login page.
Many legacy apps store passwords as MD5 or SHA-1 hashes, which are unsafe today. Laravel's documentation says its Hash facade uses bcrypt by default, with Argon2 available. We cannot convert old hashes directly, because hashing is one-way. Instead, on each user's next successful login, the old hash is checked the old way, then immediately replaced with a bcrypt hash. Laravel's docs note that Hash::check verifies the algorithm and throws an exception on a mismatch, and that you can disable that check through the HASH_VERIFY setting when supporting two algorithms during a migration, which is exactly this case.
Sessions need the same care. While old and new code run side by side, both must agree on who is logged in. We usually make Laravel the owner of the session and give the legacy scripts a small shim that reads the logged-in user from it, so one sign-in covers both halves of the app.
Users who never log in again keep their old hash until a deadline, after which they get a password reset email.
Security gains from a PHP to Laravel migration
Security is often the strongest business reason for the move, because Laravel closes the holes most commonly found in hand-written PHP by default.
SQL injection
Laravel's documentation states that its query builder uses PDO parameter binding to protect against SQL injection, so string-built queries like those in many old scripts disappear as each module moves.
Cross-site request forgery
Laravel generates a CSRF token per session, and its CSRF middleware in the web group checks it on every POST, PUT, PATCH and DELETE request. Old forms without tokens get them as they migrate.
Cross-site scripting
Blade's double-brace output is passed through PHP's htmlspecialchars automatically, so forgotten escaping in old templates stops being a risk.
Passwords
Bcrypt or Argon2 hashing through the Hash facade replaces MD5 and SHA-1, with gradual rehashing on login.
Validation and mass assignment
Form request classes validate input before controllers run, and models declare which fields may be filled, closing a common class of data-tampering bugs.
If the app has already been breached, deal with that first; our hacked website repair page explains the clean-up before any migration starts.
How do you test a PHP to Laravel migration during cutover?
Test the old behaviour before replacing it, then prove the new code behaves the same. Tests are the safety net that makes switching modules routine rather than nerve-racking.
We start with characterisation tests: automated HTTP tests that call the existing screens with known inputs and record the outputs, including database changes. They document what the app does today, bugs included. When a module is rewritten in Laravel, the same tests run against it. Differences are either fixed or consciously accepted as bug fixes, and you approve which is which.
For modules that produce numbers, such as invoices, GST totals, commission or stock levels, we also run both versions against a copy of production data and compare results row by row. A mismatch in one invoice out of thousands is easy to spot this way and very hard to spot by clicking around.
On cutover day for a module, the route switches from the legacy bridge to the new controller. Error tracking watches closely for the first hours. If something unexpected appears, the route goes back to the old script within minutes while we fix it.
- Characterisation tests on the old screens before any rewrite
- Feature tests for every migrated route, run in CI on each push
- Side-by-side output comparison for financial or stock calculations
- Staff user acceptance on staging before each switch
- A documented rollback for each module
How long does a PHP to Laravel migration take?
A mid-sized business app usually takes 6–12 weeks when migrated in slices; a small tool can be done in two or three weeks, and very large systems run longer in phases. The useful difference is that value arrives long before the end.
Week one is the audit: we read the code, map every script and table, and set up the Laravel shell in front of the app on staging. Weeks two and three move authentication and shared layout. After that, modules migrate in order of risk and value, typically one or two per week, each with its own test run and switch.
The final weeks remove the legacy bridge, tidy the schema, and hand over documentation. Throughout, you use a working production system; there is no frozen period where features stop.
Timelines slip for predictable reasons: undocumented business rules hidden in old code, integrations nobody remembered, and slow sign-off from the people who actually use each module. We surface the first two in the audit and ask for one decision-maker per module to limit the third.
Legacy PHP patterns we untangle, and what replaces them
Every legacy codebase is unique, but the same patterns turn up again and again. Knowing them helps you judge a quote.
Logic inside templates is the most expensive: a single file that checks the session, runs three queries, calculates totals and prints HTML has to be split carefully into controller, model and view. Global variables and include chains, where file A includes B which includes C, hide dependencies that only show when something breaks. Deprecated functions such as the old mysql_ extension, removed from PHP years ago, mean some files cannot run on any modern server at all.
Cron jobs are easy to forget. Old apps often have a dozen scripts triggered by the server's crontab to send reminders, clean up data or sync with accounting. In Laravel these become scheduled commands defined in code, visible in the repository and tested like everything else.
Configuration scattered across files, often with passwords in plain text, moves into environment variables that never enter the repository.
Hosting and PHP versions for the migrated Laravel app
The finished Laravel app should run on a supported PHP branch, on hosting you control. That is often the first time a legacy app has had either.
Laravel's release notes list the PHP versions each release supports; Laravel 12 supports PHP 8.2 to 8.5, and Laravel 13 requires at least PHP 8.3. The same page explains that each Laravel release receives bug fixes for 18 months and security fixes for two years. Plan an upgrade roughly once a year so you never fall far behind again.
Shared hosting that ran the old app may not suit Laravel well, because queues and the scheduler need a process running in the background. We usually set up a small cloud server or a managed Laravel-friendly platform, opened in your name, with daily database backups, SSL, a staging copy and deployment from Git. Another of us handles the server side and documents every credential in your password manager, not ours.
For the infrastructure details, see AWS setup by a freelance developer.
How to choose a developer for a PHP to Laravel migration
Choose someone who will read your old code before quoting and who talks about tests and rollback, not only about the new features Laravel offers.
Ask each candidate how they would run the old and new code side by side, what they would migrate first and why, how passwords will move, and what happens if a migrated module misbehaves on launch day. Vague answers here usually mean a big-bang rewrite in disguise.
Look for Laravel experience you can verify, but also for comfort with messy legacy PHP. The best migration developer is someone who does not panic at a 3,000-line file with SQL in the middle of the HTML.
- Did they ask for code access or a walkthrough before quoting?
- Is the quote split by module, with a separate audit stage?
- Do they explain how the database stays shared during the overlap?
- Is there a written rollback plan per module?
- Will the code live in a repository you own from week one?
If your previous developer walked away mid-project, what to do when a developer leaves covers recovering access first.
Code ownership and handover after the migration
You own the migrated code, the repository and the servers, and that should be true from the first commit, not granted at the end.
We create the Git repository in your GitHub, GitLab or Bitbucket account, or you create it and invite us. Every change is committed there. The hosting account, database and any third-party services such as SMS or email providers sit under your login and your billing.
At handover you get: the repository, a README explaining how to run the app locally, environment variable names (values stay in your password manager), deployment steps, the test suite and how to run it, a list of scheduled tasks and queues, and notes on any legacy quirks we preserved on purpose. If you later hire in-house developers or another freelancer, they start from a documented Laravel app rather than an archaeology project.
Worked example: a distributor's order portal moving from core PHP to Laravel
This is a hypothetical scenario to show the sequence, not a client story.
Say a pharmaceutical distributor in Nagpur runs a core-PHP order portal built in 2014. About 60 screens, 40 tables in MySQL, 300 retailer logins, MD5 passwords, and it only runs on an old PHP 5.6 server the hosting provider wants to retire. Staff enter orders all day; downtime means lost sales.
We would quote an audit first, then stages from ₹60,000. Week one: map every screen and table, write characterisation tests for the ordering and invoicing flows, and stand up Laravel in front of the app on a PHP 8 staging server. Weeks two and three: move login with rehash-on-login for the MD5 passwords, and the shared layout. Weeks four to nine: migrate retailer ordering, stock, invoicing with GST totals compared row by row against the old output, then reports and admin. Weeks ten and eleven: remove the legacy bridge, add missing indexes, write the handover notes.
Each module switches on a weekday evening, with a rollback route ready. After go-live the two free months of maintenance cover fixes as staff find edge cases.
PHP to Laravel migration services across India
We work remotely with businesses in every state, so the process, prices and response times do not change with your city. Calls happen on Google Meet or WhatsApp, code reviews on a shared repository, and payment by UPI or bank transfer.
City pages describe the local industries we work with: Pune, Hyderabad, Ahmedabad, Noida, Kolkata, Coimbatore, Nagpur, Vadodara, Ludhiana and Thiruvananthapuram. Clients abroad pay in USD through Wise, bank wire or PayPal.
If your old system is a Windows desktop program rather than a PHP site, read converting a desktop application to a web application instead.