Skip to main content

Cloudsoft Zone Build, deploy and scale with practical guides to PHP, Node.js, React, DevOps and AI automation. Explore the guides

Cloudsoft Zone
CodeIgniterDevelopmentPHPComparison

Moving from CodeIgniter 3 to CodeIgniter 4: what changes and how to plan it

CodeIgniter 3 is in maintenance mode and CodeIgniter 4 is a rewrite, not a drop-in upgrade. Compare the two versions, see how controllers, models, queries, views and routes translate, and plan a low-risk conversion.

Cloudsoft Zone

Updated 8 min read

Person typing on a laptop at a wooden desk with a code editor open on screen
Photograph: Crew crew / CC0, via Wikimedia Commons
In this article

Thousands of business applications still run on CodeIgniter 3: admin panels, booking systems, small SaaS products and internal tools written years ago and still earning their keep. The official download page describes CodeIgniter 3 as the legacy version, in maintenance and receiving mostly security updates, with 3.1.13 as the current release. It targets PHP 5.6 and later, while CodeIgniter 4.7 requires PHP 8.2.

The hard part is that CodeIgniter 4 is not an upgrade in the usual sense. The official guide says it plainly: version 4 is a rewrite, it is not backwards compatible, and it is "more appropriate to think of converting your app, rather than upgrading it." There is no automatic tool and no twelve-step checklist.

This article compares the two versions side by side, shows how the most common code patterns translate, and sets out a practical plan for moving an application without stopping feature work. It is written for developers doing the work and for founders deciding whether and when to fund it.

CodeIgniter 3 and 4 compared

TopicCodeIgniter 3CodeIgniter 4
StatusLegacy, maintenance mode (3.1.13)Actively developed (4.7.4, July 2026)
PHP5.6+8.2+ for 4.7
InstallationDownload and copyComposer (codeigniter4/appstarter) or zip
Entry pointindex.php in the project rootpublic/index.php; the rest of the code sits outside the web root
Code organisationNo namespaces; the $this->load superobjectPSR-4 namespaces; services, factories and Composer autoloading
RoutingAuto-routing by URL segments; $route[] arrayAuto-routing off by default; defined routes in app/Config/Routes.php; optional Auto Routing (Improved)
ConfigurationPHP arrays in application/configClasses extending BaseConfig, overridable from .env
ModelsThin CI_ModelModel with CRUD, validation, timestamps, soft deletes and pagination
Hooks$hook[] configurationEvents plus controller filters
TestingLimitedPHPUnit integration with feature-test helpers
AuthenticationThird-party librariesOfficial CodeIgniter Shield
Blue plush elePHPant toy, the PHP mascot, standing on a light grey background
CodeIgniter 3 targets PHP 5.6+, while CodeIgniter 4.7 needs PHP 8.2 or newer.

Should you migrate, and when?

A conversion costs real time, so be honest about the reasons. The strongest reasons to move are usually these:

  • PHP support. Your hosting provider or security policy needs a supported PHP version, and your CodeIgniter 3 code or its libraries do not run cleanly on it.
  • Security posture. CodeIgniter 4 keeps application code outside the web root, enables context-aware escaping with esc(), ships CSRF, secure-headers and Content Security Policy support, and has an official authentication library.
  • Hiring and maintenance. Developers who know modern PHP expect namespaces, Composer and tests. A framework in maintenance mode becomes harder to staff over time.
  • New features. APIs, queues of work and integrations are simpler to build with CI4's REST resources, transformers and Composer packages.

Reasons to wait include an application that is being retired within a year, or one with no tests and no one who understands the business rules. In that second case, spend the first weeks writing characterisation tests or documenting behaviour, not converting code.

Plan the conversion

The official advice is to start with a fresh CodeIgniter 4 project in a new folder and bring your application across component by component. A plan that works for most small and medium applications:

  1. Inventory. List controllers, models, libraries, helpers, hooks, config files and third-party packages. Mark anything that uses libraries removed in CI4: Calendaring, FTP, Javascript, Shopping Cart, Trackback, XML-RPC and Zip Encoding, plus the CAPTCHA, Email, Path and Smiley helpers.
  2. Create the new project with composer create-project codeigniter4/appstarter, and point it at a copy of the production database.
  3. Port configuration first: database, sessions, email and custom config files.
  4. Port models, because controllers depend on them.
  5. Port one module at a time (controllers, views and routes together), with tests or a manual checklist for each.
  6. Replace hooks with events and filters, and authentication with Shield or your chosen library.
  7. Run both versions side by side on staging, compare outputs, then switch traffic.

Since both versions can read the same database, a gradual move is possible: some teams route new sections of a site to the CI4 application at the web-server level while older sections stay on CI3. That needs care with sessions and shared login, so plan authentication early.

How common code translates

Controllers

Move files to app/Controllers, add a namespace, extend BaseController instead of CI_Controller, and delete the defined('BASEPATH') line. Return output instead of echoing it.

PHP
<?php
// CodeIgniter 3: application/controllers/Helloworld.php
class Helloworld extends CI_Controller
{
    public function index($name)
    {
        echo 'Hello ' . html_escape($name) . '!';
    }
}
PHP
<?php
// CodeIgniter 4: app/Controllers/Helloworld.php
namespace App\Controllers;

class Helloworld extends BaseController
{
    public function index($name)
    {
        return 'Hello ' . esc($name) . '!';
    }
}

Sub-folders become namespaces with capitalised names: application/controllers/users/auth/Register.php becomes app/Controllers/Users/Auth/Register.php in App\Controllers\Users\Auth.

Models and database code

Models move to app/Models, extend CodeIgniter\Model, and declare $table and $allowedFields. Instead of $this->load->model('x'), use model(X::class) or new X(). Query Builder method names move to camelCase and you start from a table builder:

PHP
<?php
// CodeIgniter 3
$query = $this->db->select('title')
    ->where('id', $id)
    ->limit(10, 20)
    ->get('mytable');
$rows = $query->result_array();

// CodeIgniter 4
$db      = db_connect();
$builder = $db->table('mytable');
$rows    = $builder->select('title')
    ->where('id', $id)
    ->limit(10, 20)
    ->get()
    ->getResultArray();

Other renames you will meet often: affected_rows() to affectedRows(), result() to getResult(), get_where() to getWhere() and select_max() to selectMax(). CI3's database result caching does not exist in CI4; use the Caching driver instead. One trap: limit(0) returns all rows in CI4 unless you change the setting described in the user guide (available since 4.5.0).

Long aisle of white server cabinets with perforated doors inside a data centre
Both versions can share one database, which makes a gradual, module-by-module migration possible.

Views

Views move to app/Views and mostly keep working. Replace $this->load->view('x', $data) with return view('x', $data);, and $this->load->view('x', $data, TRUE) with $html = view('x', $data);. Replace html_escape() with esc(). For page templates, CI4's View Layouts replace the header-and-footer include pattern common in CI3 projects.

Routing

This is the change that most often breaks a converted site. CI4 disables auto-routing by default, so every URL needs a route. The routing upgrade guide also notes that CI3's (:any) wildcard becomes (:segment), because (:any) in CI4 matches several segments.

PHP
<?php
// CodeIgniter 3: application/config/routes.php
$route['product/(:any)'] = 'catalog/product_lookup';

// CodeIgniter 4: app/Config/Routes.php
$routes->get('product/(:segment)', 'Catalog::productLookup');

The guide uses $routes->add() in its examples for backwards compatibility but recommends HTTP-verb routes such as get() and post() for security. If you have hundreds of URLs, you can enable Auto Routing (Legacy) temporarily, but the safer target is Auto Routing (Improved) or explicit routes.

Configuration, libraries, helpers and hooks

  • Config: custom files become classes in app/Config extending BaseConfig; $this->config->item('site_name') becomes config('Site')->siteName.
  • Libraries: namespace them and instantiate with new or Factories::libraries('X'). To replace a core class, register your own in app/Config/Services.php instead of creating a MY_ class.
  • Helpers: largely similar, and they can be autoloaded in app/Config/Autoload.php. String helper functions moved into the Text helper.
  • Hooks: become Events::on() calls; pre_controller and post_controller are gone, so use controller filters.
  • Redirects: redirect('login/form') becomes return redirect()->to('login/form');. It returns a response object instead of exiting.
  • Input and output: CI3's Input class maps to IncomingRequest, and Output maps to the Response object.

Pitfalls that catch most teams

The official upgrade notes contain several small changes that cause confusing bugs if you miss them during a conversion:

  • Redirects must be returned. In CI3, redirect() sent headers and stopped the script. In CI4 it returns a RedirectResponse; if you call it without return, execution carries on and the redirect never happens. Cookies and headers set before the redirect are not carried over automatically either, so call withCookies() or withHeaders() when you need them.
  • HTTP method names are uppercase. Since 4.5.0, CI4 uses GET and POST rather than the lowercase names CI3 used. Code that compares $this->request->getMethod() to 'post' will silently fail.
  • No more BASEPATH. CI4 does not define the constant, so the old defined('BASEPATH') OR exit(...) guard at the top of each file will stop it from running. Remove the line everywhere.
  • Removed hook points. pre_controller and post_controller no longer exist; move that logic into controller filters. display_override and cache_override are gone too.
  • Errors stop execution. In CI4, any error not ignored by error_reporting() stops the framework, so notices that CI3 logged quietly may now surface as failures. Fix them rather than lowering the error level.
  • The testing environment is reserved. CI4 uses testing for PHPUnit only. If you had a CI3 environment named "testing" for a staging server, rename it and create a matching boot file in app/Config/Boot/.

Passwords deserve a separate note. If your CI3 application stores hashes created with PHP's password_hash(), any PHP 8 code can still check them with password_verify(), so users can keep their passwords. If it uses an older custom scheme, plan a rehash-on-login step before you switch, and test it with real (anonymised) accounts on staging.

Effort and risk at a glance

AreaTypical effortMain risk
ViewsLowMissed escaping when changing echo syntax
Models and queriesMediumRenamed methods, limit(0) behaviour, missing $allowedFields
ControllersMediumCode that relied on the superobject or on exit after redirects
RoutingMedium to highBroken URLs and lost SEO if routes are missed
Authentication and sessionsHighLocking users out, password hash compatibility
Removed librariesVariesFinding Composer replacements

For public sites, export the full list of indexed URLs before you start and test that each one returns the same page, or a 301 redirect, on the new application.

Next steps

Start small: create a CI4 project, connect it to a copy of your database, and port one read-only section end to end. That first module shows the real cost of the conversion far better than any estimate. Once it works, put the remaining modules in a tracked list, port them in order of business value, and keep the CI3 application running until every route has a tested CI4 equivalent. After the switch, upgrades within CodeIgniter 4 are routine: read each release's upgrade notes and run composer update.

Frequently asked questions

  • Can I upgrade CodeIgniter 3 to 4 with Composer?

    No. CodeIgniter 4 is a rewrite and is not backwards compatible. The official guide recommends starting a new CI4 project and converting your application's components into it.

  • Is CodeIgniter 3 still supported?

    The CodeIgniter download page describes version 3 as legacy and in maintenance, receiving mostly security updates. The current CI3 release is 3.1.13.

  • Can CodeIgniter 3 and 4 use the same database?

    Yes. Both work with the same MySQL or other supported database, which allows a gradual migration. Plan sessions and login carefully if both applications serve users at the same time.

  • Why do my CI3 URLs return 404 in CodeIgniter 4?

    Auto-routing is disabled by default in CI4. Define routes in app/Config/Routes.php, or enable Auto Routing (Improved). Also change (:any) wildcards to (:segment).

Advertise on CloudSoftZone

Your next customer could start right here.

Introduce your tool, product or business to readers exploring technology.

Advertise with us

Explore placements and request a private quote

Sources

  1. Upgrading from 3.x to 4.x — CodeIgniter Foundation
  2. Upgrade Controllers — CodeIgniter Foundation
  3. Upgrade Models — CodeIgniter Foundation
  4. Upgrade Database — CodeIgniter Foundation
  5. Upgrade Routing — CodeIgniter Foundation
  6. Upgrade Views — CodeIgniter Foundation
  7. Upgrade Configuration — CodeIgniter Foundation
  8. Download CodeIgniter — CodeIgniter Foundation

Written with substantial AI assistance. Facts checked against cited sources. Editorial policy.

Comments

No comments yet. Be the first to join the conversation.

Leave a comment

Every comment is read by a moderator before it appears. Your email address is never published; it is used only to contact you about this comment.

Never published. Used only to contact you about this comment.

Loading the security check…

Comments are moderated before publication.