Moving off CodeIgniter one module at a time, with both applications live behind a router and a rollback available at every step.
CodeIgniter applications that are still running a business are usually a decade old, undocumented, and correct about things nobody remembers. A full rewrite means reproducing all of that from the code, in one attempt, and switching over on a single evening. The failure rate for that approach is well documented.
The Strangler Fig pattern replaces it with a series of small moves. A router sits in front of both applications and sends a URL prefix to Laravel while everything else continues to hit CodeIgniter. Sessions are shared, the database is shared initially, and each migrated module can be reverted by changing one routing rule.
The unglamorous part is session and auth compatibility, and it is what makes the whole approach work. Our legacy PHP migration guide goes through the mechanics.
Teams that start here often pair it with CakePHP and Yii modernisation, CodeIgniter to MERN migration and custom software development.
A rewrite asks you to be right about ten years of business rules in one attempt. A strangler migration asks you to be right about one module at a time.
Four reasons the big-bang approach keeps disappointing.
A decade of business logic lives only in the code, so any behaviour the rewrite misses becomes a production incident after cutover.
The business waits eighteen months while both codebases are maintained, and the pressure to ship eventually forces a premature switch.
Everything moves on a single evening with no partial rollback, so any serious problem means an all-night revert.
The database is redesigned at the same time as the application, so two hard problems fail together and neither can be isolated.
Continuous delivery of new value while the legacy system shrinks.
A reverse proxy in front of both applications, routing by URL prefix, so traffic can move module by module and back again.
A common session store and compatible auth, so a user moving between old and new pages never notices a boundary.
Sequence chosen by business value and risk, so the modules that are painful today move first.
Both applications on the same database initially, with schema changes made compatibly so either side can read.
Characterisation tests capture existing behaviour before each module moves, so parity is proven rather than assumed.
Each module released behind a flag with monitoring, reverted by a routing change if the numbers disagree.
Value delivered from the first month, not the final one.
Modules, dependencies, traffic and business criticality mapped, with the migration sequence agreed against risk.
Laravel application, shared session store, routing layer and CI, with one low-risk module moved to prove the path.
Modules moved in sequence, each with characterisation tests, a flagged release and a routing-level rollback.
Schema improvements applied compatibly once traffic for a table sits mostly on the new side.
The last CodeIgniter routes retire and the legacy application is switched off, by which point it serves nothing.
Modern Laravel, with the legacy application left alone until its turn.
Current Laravel with a supported upgrade path, replacing a framework that reached end of life years ago.
A proxy layer that makes the migration boundary a configuration value.
Shared sessions and compatible password hashing so users never see the seam.
Behaviour captured before it moves, so parity is a test rather than an opinion.
A logistics operator ran their entire operation on CodeIgniter 2 with PHP 5.6, unsupported for years and increasingly impossible to hire for. Two previous rewrite attempts had been abandoned after roughly a year each.
We started with a routing layer and moved reporting first: high visibility, low risk, and no writes. That single module took six weeks including the shared session work, and it proved the approach to a sceptical board.
Eighteen months later the CodeIgniter application served three administrative screens. Nobody could name the day the platform became a Laravel application, which was the point.
Both applications run side by side behind a router. Every module that moves can move back with a configuration change, which is why these migrations finish.
We move one slice at a time behind a router, with both systems live, so every step is small and every step is reversible.
A working demo and a written note every Friday covering what shipped, what slipped and what it means for the date. No status theatre.
Nothing goes live in one jump. We run in parallel or behind a flag until the numbers say it is safe to switch over.