Upgrade guide
composer.lock records the exact versions of the FloCMS packages a site installs. Use composer install for repeatable deployments and update dependencies deliberately. Upgrade one site at a time, and test before you deploy.
Composer updates packages but never your project's own files (controllers, views, config/), so each section says which files to copy from the new skeleton. A site that copies nothing keeps working; it just doesn't get those changes.
Core 2.9: SQLite for websites
composer update hostkurd/flocms-core
Nothing else changes. To run a site on SQLite, see database. Sites with DB_TYPE=sqlite in .env only for php flo now connect to that file on the website too: set DB_TYPE=mysql if the website should keep using MySQL.
From 1.8 to 2.0
Existing sites keep working as they are: each site owns its composer.json, and flocms-api 1.3 keeps the old class names. To follow 2.0:
-
Update core and the API together:
composer require "hostkurd/flocms-core:^2.8" "hostkurd/flocms-api:^1.3" -W -
Change the rate-limit and client IP imports from the API to core in
support/LoginThrottle.php,controllers/UsersController.phpandincludes/maintenance.php:use FloCMS\Core\RateLimit\FileRateLimiter; // was FloCMS\Api\RateLimit\FileRateLimiter use FloCMS\Core\RateLimit\RateLimiterInterface; // was FloCMS\Api\RateLimit\RateLimiterInterface use FloCMS\Core\Security\ClientIpResolver; // was FloCMS\Api\Security\ClientIpResolver use FloCMS\Core\Security\IpMatcher; // was FloCMS\Api\Security\IpMatcher -
A site without an API can then remove it:
composer remove hostkurd/flocms-api, and deletepublic/api.phpandapi/. Keep them if anything calls/api/v1. -
Optional: copy
commands/SetupCommand.phpto add the admin panel or the API later withphp flo setup, and thehomesetting: theConfig::set('home', 'site')line ofconfig/config.phpand the lines that read it at the start ofPagesController::index(), with itshome()method. See choose what you build.
From 1.7 to 1.8
-
Move to caret ranges and a current core. In
composer.json, change the exact versions of the framework packages to ranges ("hostkurd/flocms-core": "^2.6","hostkurd/flocms-cli": "^2.0.1","hostkurd/flocms-uploader": "^1.2.1","hostkurd/flocms-captcha": "^1.1.0","hostkurd/flocms-api": "^1.2.0"), then:composer update -W -
Admin pages. The skeleton's unfinished user pages were removed in 1.8.0. If your site uses
UsersController::admin_index,admin_add,admin_edit,admin_profile,admin_delete,admin_verifyoradmin_suspend, keep your copies; Composer doesn't delete them. To use the admin panel instead, see admin panel. -
/adminand the admin panel. Copyadmin_index()andadminHome()from the skeleton'scontrollers/PagesController.php, so/adminopens the admin panel's dashboard (theadmin.homesetting). -
Admin layout. In
templates/default/layouts/admin.html, load the stylesheets and scripts withtemplate_asset()(1.7.8), and copy thelanganddirattributes of the<html>tag (1.8.3). -
Roles. Copy the
Auth::hasAdminAccess()lines ofadmin_login()incontrollers/UsersController.php(1.8.7), so roles added in the admin panel can sign in at once. Add'activity.view'to role 2 inconfig/config.phpif Admins should see the admin panel's activity log (1.8.6). -
The settings table. If the site has no
settingstable, copydatabase/migrations/2026_10_17_000000_create_settings_table.phpand runphp flo migrate(1.8.5). -
Pages from the admin panel. Copy the
home_page()lines at the start ofPagesController::index()and thepage_meta()andblocks_assets()lines oftemplates/*/layouts/default.html(1.8.8). Without flocms-admin's Pages they do nothing.
If you're on 1.7.5 or older, also follow the steps below.
From 1.7.5 to 1.7.8
composer require hostkurd/flocms-core:2.3.0
- 1.7.6 (core 2.2.3): the
maxrule passes on an empty value. If you relied onmaxto reject empty input, addrequired. - 1.7.7 (core 2.3.0): controller resolvers. Nothing changes until a package registers one.
- 1.7.8: copy the five changed lines of
templates/default/layouts/admin.html(step 4 above).
From 1.7.x to 1.7.5
-
Require the new core and captcha releases:
composer require hostkurd/flocms-core:2.2.2 hostkurd/flocms-captcha:1.1.0 -
Compiled templates are rebuilt automatically, because the template compiler version changed. Run
php flo optimizeafter deploying if you compile templates ahead of time. -
If your code calls the captcha's
verify()twice for the same answer, the second call now fails, because codes are single-use. Check once and keep the result, or set'single_use' => falsein the captcha configuration. Callingclear()afterverify()still works; it's just no longer needed. See captcha. -
If you renamed multi-word view folders to
views/blog_post/style and link to/blog_post, that keeps working./blog-postnow works too, with views inviews/blog-post/.
If you're on 1.7.3 or older, also follow the 1.7.4 steps below.
From 1.7.x to 1.7.4
-
Require the core security release:
composer require hostkurd/flocms-core:2.2.1 -
Optional: add the admin dashboard from 1.7.3, so
/admin/no longer answers 404 after login. Copyadmin_index()from the skeleton'scontrollers/PagesController.php, the viewviews/pages/admin_index.html, and therolesblock fromconfig/config.php. -
Check your controllers for public helper methods. Public methods on your controller or your own base controller can be reached from a URL, so make helpers
protectedorprivate. Since core 2.2.1, methods inherited fromFloCMS\Core\Controller, protected/private/static methods and magic method names answer 404.
From 1.6 to 1.7
-
Composer. In
composer.json, require"hostkurd/flocms-cli": "2.0.1"and"hostkurd/flocms-api": "1.2.0", add"App\\Commands\\": "commands/"toautoload.psr-4, and runcomposer update. -
Launcher. Replace the root
flofile with this one, a one-time step:#!/usr/bin/env php <?php require __DIR__ . '/vendor/autoload.php'; exit(FloCMS\CLI\Kernel::handle(__DIR__, $argv));Then delete
support/KeyGenerator.php. -
Maintenance mode. Copy
includes/maintenance.phpandtemplates/default/errors/503.html, and the maintenance lines ofpublic/index.phpandpublic/api.php. -
Optional.
- Copy
commands/LoginUnlockCommand.phpand theunlockIp()method ofsupport/LoginThrottle.php. - Copy
config/schedule.phpand add the cron job.
- Copy
-
Check. Run
php flo doctorandphp flo migrate. The API tables are only recorded when they already exist.
Note
Sites created before 1.6 follow the same steps. Until the flo file is replaced, composer update gives them flocms-cli 1.0.5, and its "command not found" message points to these steps.
After upgrading
- Run
php flo env:checkto find new.envkeys. - Run
php flo view:clearso templates are compiled again. - Read the release notes for what changed.
Moving older API code
FloCMS\Core\Api and FloCMS\Core\ApiController are deprecated. The API package also supplies FloCMS\Api\Legacy\LegacyApiController as a compatibility bridge, but new endpoints should use FloCMS\Api\Controller.
- Move handlers into
api/Controllers/with theApp\Api\Controllersnamespace. - Declare each HTTP method/path in
api/routes.php, with authentication and rate limits where needed. - Replace global input/query access with the handler's
Requestargument. Positional page parameters become named API route parameters. - Return
Responseobjects or resources rather than echoing JSON and exiting. Use the controller helpers for the response envelope. - Test clients against the
/api/v1URLs, response bodies and status codes, then leaveLEGACY_API=false.
Keeping a compatibility class does not configure explicit routes, middleware or authorization for you. See building an API.