Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Framework Laravel Package

codeigniter4/framework

CodeIgniter 4 is a lightweight, fast PHP framework for building dynamic web apps. It offers MVC structure, minimal configuration, strong security tools, and a small footprint, making development simple and efficient.

View on GitHub
Deep Wiki
Context7

Getting Started

codeigniter4/framework is not a library you drop into an existing app — it is the application skeleton's engine (system/), and you almost never reference it directly in business code. Day-to-day you work in a project generated from codeigniter4/appstarter, which pulls this package in via Composer.

composer create-project codeigniter4/appstarter my-app
cd my-app
cp env .env                 # set CI_ENVIRONMENT = development, app.baseURL
php spark serve             # http://localhost:8080, PHP built-in server

First place to look:

  1. app/Config/Routes.php — all routing; nothing is reachable without a route (auto-routing is off by default).
  2. app/Config/App.php — $baseURL must be right or site_url(), redirects, and assets break.
  3. app/Controllers/BaseController.php — shared helpers, initController(), auth guards.
  4. app/Config/Filters.php — the middleware equivalent ($globals, $aliases, $required).
  5. vendor/codeigniter4/framework/app/Config/ — the canonical copies of every config file you own in app/Config/.

First use case: a thin CRUD endpoint. php spark make:controller Users --restful, php spark make:model UserModel, php spark make:migration CreateUsers, write the up() forge call, php spark migrate, wire $routes->resource('users'), inject the model in initController(), return $this->response->setJSON($rows). That loop — generate, migrate, route, respond — is the whole framework in miniature.

For a Laravel developer the mental mapping is: Artisan → Spark, Eloquent → Models + Entities (Active Record/Query Builder), Blade → plain PHP views, Middleware → Filters, Service Providers → Events + Config\Services, Facades → service()/helpers, model factories → Seeders/Fakers. Queueing, auth, and settings live in separate packages (codeigniter4/shield, codeigniter4/queue, codeigniter4/settings) — the core deliberately stays small.

Implementation Patterns

Routing and grouping. Closures are fine for prototypes; production goes through controllers. Group by filter and prefix:

$routes->group('api/v1', ['namespace' => 'App\Controllers\Api'], static function ($routes) {
    $routes->get('users/(:num)', 'Users::show/$1');
    $routes->resource('posts', ['except' => ['new', 'edit']]);
});

php spark routes prints the resolved table — reach for it the moment a 404 is unexplained (trailing slash, verb mismatch, filter rejection all surface here).

Models as the unit of data access. The model is where $allowedFields, $validationRules, $useTimestamps, $returnType, and $casts live. Prefer entities ($returnType = User::class) over the default array so $user->created_at is a Time object and $user->toArray() gives you the API shape. Use model('UserModel') or DI in the constructor; keep Query Builder chains in the model, not the controller.

Filters for cross-cutting concerns. Register aliases and apply them per-route rather than sprinkling logic in BaseController:

public array $aliases = ['auth' => \App\Filters\AuthFilter::class, 'throttle' => ...];

A filter returns $request to continue or a Response to short-circuit — the same shape as Laravel middleware, but there is no $next($request) closure.

Responses and validation. ResponseTrait ($this->respond(), $this->failValidationErrors()) standardizes API payloads; $this->validate([...]) runs inline rules and populates $this->validator->getErrors(). For forms, put rule sets in Config\Validation::$user and call $this->validate('user') so the same rules serve HTML and JSON.

Config over code. Every knob is a class property in app/Config/*. .env values override them at runtime using classname.property keys (database.default.hostname, app.baseURL). This means one deployable image + per-environment .env, no config caching step.

Testing. Use CIUnitTestCase + FeatureTestTrait for HTTP-level assertions and DatabaseTestTrait with $refresh = true, $namespace = 'App', $migrate = true for a real schema per test. Services::reset() between tests clears the shared service instances — skipping it is the source of most flaky suites.

Commands. Anything you would write as an Artisan command is an App\Commands\* class extending BaseCommand; auto-discovered from app/Commands, invoked via php spark your:command.

Gotchas and Tips

  • app/Config is a fork, not a symlink. composer update upgrades system/ but never touches your config copies. After every upgrade, diff app/Config/ against vendor/codeigniter4/framework/app/Config/ and merge new properties by hand — missing properties cause silent behavior changes rather than errors (php spark config:check catches some of this).
  • Never edit system/ or anything in vendor/. Override through Config\Services (register a replacement for a framework service), Events (Events::on('pre_system', ...)), or by extending the class in app/Libraries. The repo's own guidance — "dependencies should be injectable", "prefer the minimum useful abstraction" — is the same discipline you apply in your app.
  • $allowedFields is mandatory. An empty array silently blocks all inserts/updates while find() still works, so reads pass and writes no-op. Pair it with $protectFields = true and never call skipValidation() casually.
  • Auto-routing is off. It also cannot see controller methods with parameters in some shapes; don't enable setAutoRoute(true) in production — explicit routes plus spark routes are your safety net.
  • Filters don't run on CLI, so anything session- or auth-dependent will behave differently under Spark commands and queue workers. Guard with is_cli().
  • Validation state is controller-scoped. validate() returns bool and stashes the validator on $this->validator; call getErrors() after the failed check, not on a fresh instance.
  • Sessions write to writable/session with the file handler by default. In containers, point Config\Session::$savePath at a mounted volume or switch to a shared handler, or logins evaporate across replicas.
  • Debug toolbar and Kint are development-only and are configured through Config\Toolbar / Config\Kint. They add measurable overhead and leak query data — confirm CI_ENVIRONMENT before profiling anything in staging.
  • Long-running worker mode (FrankenPHP) reuses one process. public/frankenphp-worker.php is generated from a template; if you've customized it, framework upgrades will not propagate fixes — republish with php spark worker:install --force and re-apply your edits. Static state and open connections are per-process, so any request-scoped cache you add must be reset explicitly.
  • Model find() returns null, not an exception. Build a findOrFail-style helper in your base model if you're used to Laravel's behavior.
  • composer.json pins a minor line and the project follows semver-with-caveats: develop accepts no BC breaks, 4.* allows narrow, documented ones. Read the upgrading guide on every minor bump; deprecated APIs survive at least two minors, so pin deliberately.
  • Where the framework earns its keep: near-zero boot cost, no container auto-wiring to debug, config-as-PHP that greps cleanly, and a test harness that boots in milliseconds. Where it costs you: no ORM relationship magic, no queued-jobs/horizon equivalent in core, fewer first-party packages — budget for codeigniter4/shield and friends on day one rather than retrofitting auth later.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource