The go-to resource for learning PHP, Laravel, Symfony, and your dependencies.

The Developer's Guide to the October CMS Laravel Upgrade Path


Between 1939 and 1945, the United States Census Bureau faced a mounting crisis. The decennial census, mandated by the Constitution, had become increasingly unwieldy. The 1880 census had taken eight years to process; experts believed the 1890 census could take over a decade — meaning results would be obsolete before they were complete. The population had grown exponentially, and the manual tabulation methods were reaching their breaking point. Something had to change.

The solution arrived in the form of Herman Hollerith’s electromechanical tabulating machine. This innovation — using punched cards, electrical circuits, and counting mechanisms — automated what had been a painstaking manual process. The 1890 census was processed in just one year, a stunning improvement. The technology evolved, eventually leading to the formation of IBM. The lesson: when manual processes become unsustainable, systematic automation transforms the possible.

Upgrading the Laravel foundation within October CMS presents a similar challenge. The Laravel ecosystem has evolved rapidly over the years — Laravel 5.x gave way to 6.x (with LTS), then 7.x, 8.x, 9.x (another LTS), and now 10.x and 11.x. Each major release brings breaking changes, deprecated features, and new capabilities. Meanwhile, October CMS must align its own releases with specific Laravel versions, creating a version matrix that developers must navigate.

So far, we’ve discussed the general need for upgrades. But let’s take a step back and survey the landscape: what approaches exist for managing Laravel versions in an October CMS project? The ecosystem offers several possibilities, each with its own philosophy and trade-offs.

One might consider simply updating Laravel directly, as one would in a vanilla Laravel application. That approach, though, runs into October CMS’s architecture — October CMS bundles a specific Laravel version within its october/all package and makes careful adjustments to ensure plugins and core functionality work seamlessly. Upgrading outside this structured path leads to compatibility issues, broken plugins, and subtle bugs.

Another approach might be to ignore October CMS’s constraints and manually specify Laravel versions in composer.json. This gives more control but requires deeper expertise and carries substantial risk — October CMS expects certain Laravel APIs and behaviors; deviating can cause system failures.

A third possibility is to abandon October CMS entirely and migrate to vanilla Laravel. This is a major undertaking, effectively rebuilding your CMS functionality. It may make sense for applications that have outgrown October CMS’s capabilities, but for the majority of users, it’s disproportionate to the problem.

This guide focuses on the first approach — working within October CMS’s managed upgrade framework — because it addresses the limitations of the alternatives: it provides stability through compatibility testing, reduces maintenance burden, and respects the October CMS ecosystem. The other approaches have their place, but they serve different needs than the typical October CMS user faces. We’ll explore them briefly in a dedicated section, but our primary focus remains the structured, tested upgrade path that October CMS provides.

By the end of this guide, you’ll have not just a working upgraded application, but the accumulated wisdom to handle future upgrades with confidence. Let’s begin with understanding the version relationships that make this all possible.

Understanding the Laravel Upgrade Challenge in October CMS

Upgrading the underlying Laravel framework within October CMS is not just about chasing version numbers — it brings tangible benefits like enhanced security, performance improvements, new features, and long-term support. However, this process requires careful planning because October CMS has its own release cycle that aligns with specific Laravel versions. Understanding this relationship is crucial for a successful upgrade that maintains compatibility with your existing plugins and themes.

Approaches to Laravel Version Management

Before diving into the step-by-step process, let’s examine the available approaches. One may wonder: what options do you actually have for managing Laravel versions in an October CMS project? There are several paths, each with distinct trade-offs.

Option 1: October CMS Managed Upgrades (Recommended for Most Users)

This is the standard approach: you let the october/all package manage the Laravel version through its dependency constraints. You upgrade by updating the october/all version constraint in your composer.json, and Composer resolves all Laravel components automatically.

Advantages:

  • Compatibility is guaranteed — the October CMS team tests each release against its target Laravel version.
  • Plugin and theme compatibility is managed through October CMS’s version constraints.
  • Minimal configuration — you don’t need to track individual Laravel component versions.
  • Future upgrades remain straightforward as October CMS provides clear upgrade paths.

Disadvantages:

  • You’re limited to the Laravel versions that October CMS officially supports.
  • If you need a specific Laravel patch version for security reasons, you must wait for October CMS to update its constraints.
  • Less control over the exact versions of individual Laravel components.

This approach works well for the majority of October CMS users — indeed, it’s what the October CMS team recommends and designs for.

Option 2: Explicit Laravel Version Specification

You can add laravel/framework to your composer.json with an explicit version constraint, overriding the version that october/all would otherwise install. This gives you more control but requires more care.

Advantages:

  • You can target specific Laravel versions, including security patch releases.
  • More granular control over your dependency tree.
  • Can sometimes bypass delays in October CMS package updates.

Disadvantages:

  • You risk compatibility issues — October CMS expects certain Laravel versions and may break if you deviate.
  • You must carefully test plugin compatibility yourself.
  • You take on responsibility for ensuring all Laravel components work together harmoniously.
  • Future upgrades become more complex as you must manage constraints manually.

We recommend against this approach unless you have a specific, documented need — such as a critical security fix that October CMS hasn’t yet incorporated. Even then, proceed with extreme caution and comprehensive testing.

Option 3: Migration to Vanilla Laravel

Some teams consider migrating away from October CMS entirely to a vanilla Laravel application. This is effectively a rewrite — you rebuild your content management on Laravel without October CMS’s abstractions.

Advantages:

  • Complete control over your stack — no constraints from October CMS’s release cycle.
  • Can use any Laravel feature immediately, without waiting for October CMS to integrate it.
  • Simplified dependency tree (fewer layers).
  • Potentially better performance by removing abstraction layers.

Disadvantages:

  • Significant development effort — you must rebuild CMS functionality, admin interfaces, and possibly plugins.
  • Loss of October CMS’s ecosystem (plugins, themes, community).
  • Higher maintenance burden — you’re responsible for all CMS features yourself.
  • Migration risk is substantial; this is not an “upgrade” but a reconstruction.

This approach makes sense only if you’ve outgrown October CMS’s CMS capabilities and are willing to invest in a custom solution. For most October CMS users, staying within the October ecosystem is the pragmatic choice.

Option 4: Hybrid Approaches

Some teams use hybrid configurations: keeping October CMS for content management while integrating raw Laravel components for custom features. This is valid and encouraged — October CMS is built on Laravel, after all, and you can access Laravel services directly through the container.

This sits somewhere between options 1 and 3; it doesn’t change your October CMS upgrade path but affects how you write custom code. We’ll touch on this in the section “Using Direct Laravel Components.”

Making the Choice

For readers wondering which path to take: if you’re maintaining a standard October CMS application with plugins and themes from the marketplace, Option 1 is almost certainly your best choice. It provides stability, community support, and a clear upgrade path. Options 2 and 3 should be considered only after careful evaluation of your specific requirements and resources.

With this understanding of approaches, let’s proceed with the standard October CMS managed upgrade path — the one that will serve most readers best.

One may wonder: why can’t we simply upgrade Laravel directly like we would in a vanilla Laravel application? The answer lies in October CMS’s architecture. October CMS bundles a specific Laravel version within its october/all package and makes careful adjustments to ensure its plugins and core functionality work seamlessly. Upgrading outside this structured path can lead to compatibility issues, broken plugins, and subtle bugs that are difficult to diagnose. So we must work within October CMS’s version constraints — understanding which Laravel versions correspond to which October CMS releases.

For example, October CMS version 2.x was built on Laravel 5.x and 6.x, while October CMS 3.x requires Laravel 8.x or 9.x. The October CMS team rigorously tests each release against its target Laravel version to ensure stability, so it’s essential to follow their compatibility matrix. As of March 2026, the current stable release of October CMS is 3.2.x, which is compatible with Laravel 9.x. If you’re running an older version like October CMS 2.x, you’ll need to upgrade to 3.x first — you cannot jump directly from October CMS 2.x to 3.x using a different Laravel path.

Now, you might be asking: are there alternative approaches? We’ll explore this more later, but broadly speaking, you have three options: let October CMS manage the Laravel version through its package constraints, explicitly specify a Laravel version in your composer.json, or perform a migration to vanilla Laravel if you want to move away from October CMS. For most October CMS users, the first two approaches within the October CMS ecosystem are the most practical — though the second gives you more control, it also requires more care to avoid conflicts.

Prerequisites

Before starting the upgrade process, you’ll need to have a few things in place. Of course, you need your October CMS application — any version will work, though very old versions (pre-1.x) may require additional steps. You also need:

  • File and database access: Full access to your project’s files and database credentials. You’ll be modifying code and running database migrations.
  • Composer: PHP’s package manager must be installed and accessible from your command line. You should be comfortable running Composer commands.
  • Laravel and October CMS familiarity: Basic understanding of Laravel’s service container, middleware, and October CMS’s plugin system will help you diagnose issues.
  • A testing environment: We strongly recommend — indeed, we insist — that you perform the upgrade in a development or staging environment first. Never upgrade a live production site without testing. Though it may be tempting to skip this step when you’re confident, we’ve seen many cases where a seemingly minor version jump introduces subtle plugin conflicts that only surface under production load.

You may wonder: can I do this on shared hosting? The answer is: it depends. You’ll need SSH access to run Composer and Artisan commands, and sufficient permissions to write to the storage and bootstrap/cache directories. If your hosting provider restricts these, you may need to upgrade locally and then upload the updated files.

Why Upgrade Laravel within October CMS?

Upgrading the underlying Laravel framework is not just about chasing version numbers. It brings tangible benefits:

  • Enhanced Security: Access the latest security fixes from the Laravel community, protecting your application from vulnerabilities.
  • Performance Improvements: Benefit from optimizations in the framework’s core, leading to faster response times and a better user experience.
  • New Features: Leverage new capabilities introduced in recent Laravel versions, such as improved job batching, enhanced routing, and modern syntax.
  • Long-Term Support (LTS): Aligning with an LTS version of Laravel ensures your application receives security and bug fixes for an extended period.

Before You Start: The Pre-Upgrade Checklist

A smooth upgrade begins with proper preparation. We cannot stress this enough: do not skip these steps. The time you spend preparing will save you hours of frustration later — and potentially catastrophic data loss.

1. Full Backup (Essential)

First and foremost, create a complete backup of your application. This is non-negotiable. Should anything go wrong, you must be able to restore your application to its working state. One may wonder: what constitutes a “complete” backup? Let’s be explicit.

Database Backup

Export a full SQL dump of your entire database. Use the appropriate tool for your database system:

For MySQL or MariaDB:

$ mysqldump -u username -p --routines --triggers --single-transaction database_name > backup-$(date +%Y%m%d-%H%M%S).sql

The --routines and --triggers flags ensure stored procedures and triggers are included. The --single-transaction flag creates a consistent snapshot without locking tables (for InnoDB).

For PostgreSQL:

$ pg_dump -U username -Fc database_name > backup-$(date +%Y%m%d-%H%M%S).dump

Store this backup in a secure location separate from your application server — preferably offsite or at least on a different physical disk. Verify the backup is valid:

$ gzip -t backup.sql.gz  # if compressed
# or for PostgreSQL custom format:
$ pg_restore -l backup.dump  # lists contents without restoring

If the backup verification fails, recreate it before proceeding.

Filesystem Backup

Create an archive of your entire project directory:

$ tar -czf project-backup-$(date +%Y%m%d-%H%M%S).tar.gz /path/to/your/project

You might ask: do I really need to back up the vendor/ directory? The answer is yes. While you could regenerate dependencies with Composer (composer install), having a backup ensures you can roll back to the exact state you started from, including exact package versions. It’s better to have it and not need it than the reverse. Additionally, if your Composer repository access is interrupted during rollback, having the vendor directory in the backup saves you from dependency resolution headaches.

Multiple Backup Strategy

We recommend the 3-2-1 rule: three copies of your data, on two different media, with one copy offsite. At minimum, have:

  1. The live site’s current files and database (already there).
  2. A backup stored on the same server (different disk partition).
  3. A backup stored remotely (another server, cloud storage, etc.).

Test restoring from your backup before proceeding. A backup you haven’t verified is not a backup — it’s an assumption.

2. Review October CMS Release Notes

Consult the official October CMS release notes to understand the corresponding Laravel versions. The mapping is not always straightforward — October CMS 3.x, for instance, has evolved through Laravel 8.x to 9.x as the project progressed. For example, October CMS 3.0 initially required Laravel 8.x, while later 3.x releases moved to Laravel 9.x. Knowing the exact target version for your specific October CMS release is crucial. You’ll find this information in the composer.json of the October CMS skeleton or in the official upgrade documentation.

One may wonder: where exactly do you find this mapping? Look in the October CMS GitHub repository’s composer.json for the october/all package. The require section will show the Laravel component constraints. For October CMS 3.2, you’ll see constraints like "illuminate/support": "^9.0", indicating Laravel 9.x compatibility. Additionally, the October CMS documentation includes a version compatibility matrix. Bookmark it for reference.

3. Check Plugin and Theme Compatibility

This is the most common point of failure — we’ve seen many upgrade attempts stymied by incompatible plugins. Verify that all your installed plugins and your active theme are compatible with the target versions of both October CMS and Laravel. Here’s how:

  • Check the October CMS marketplace listing for each plugin; look for version compatibility information.
  • Visit the plugin’s GitHub repository and review the composer.json constraints.
  • Contact the plugin developers directly if compatibility isn’t clear.
  • For maintained plugins, you’ll often see something like "october/rain": "^1.30" or "illuminate/support": "^9.0" which indicates Laravel 9.x compatibility.
  • If a plugin hasn’t been updated in years and shows no signs of maintenance, you may need to look for alternatives or be prepared to fix compatibility issues yourself.

One may wonder: what if a critical plugin isn’t compatible? You have a few options: fork the plugin and update it yourself (if the codebase is small and well-documented), contact the developer to request an update, replace the plugin with an alternative, or delay your upgrade until compatibility is resolved. There’s no universal answer — it depends on your specific dependencies and their importance to your application.

We recommend creating a plugin compatibility matrix before upgrading:

PluginCurrent VersionTarget October CMSLaravel CompatibilityStatus
RainLab.User2.10.43.2^9.0✅ Compatible
Vendor.Plugin1.5.03.2^5.5❌ Update needed

This matrix will guide your upgrade planning. If a critical plugin shows ❌ and there’s no compatible version, you’ll need to address that before proceeding (either by finding an alternative or by preparing to maintain a fork).

4. Check System Requirements

Ensure your server environment meets the requirements for the target Laravel version. Pay close attention to:

  • PHP version: October CMS 3.x typically requires PHP 8.0.2 or higher; October CMS 2.x may run on PHP 7.2.9 or higher. Verify your server’s PHP version with php -v or php --version. Also check the web server’s PHP version, which may differ from CLI.

  • PHP extensions: Laravel requires several extensions such as openssl, pdo, mbstring, tokenizer, xml, curl, bcmath, and gd or imagick. Your target Laravel version may add new requirements. For Laravel 9.x and October CMS 3.x, the minimum extensions are:

    • php >= 8.0.2
    • ext-ctype
    • ext-curl
    • ext-gd or ext-imagick
    • ext-iconv
    • ext-json
    • ext-mbstring
    • ext-pdo
    • ext-tokenizer
    • ext-xml

    Additional extensions may be required by your specific plugins (e.g., ext-zip for certain file operations, ext-bcmath for precise math).

  • Composer version: Ensure you’re running a recent Composer version (2.x). Older Composer 1.x may have issues with newer packages. Check with composer --version. If you see Composer version 1.x.x, upgrade Composer before proceeding.

You can check your current PHP extensions with php -m. If you’re missing required extensions, you’ll need to install them before proceeding. On Ubuntu/Debian, for example, you might run:

$ sudo apt-get install php8.1-mbstring php8.1-xml php8.1-curl php8.1-bcmath php8.1-gd php8.1-zip php8.1-intl

Adjust for your PHP version. After installing extensions, restart your web server and PHP-FPM if applicable, then re-run php -m to confirm they’re loaded.

2. Review October CMS Release Notes

Consult the official October CMS release notes to understand the corresponding Laravel versions. The mapping is not always straightforward — October CMS 3.x, for instance, has evolved through Laravel 8.x to 9.x as the project progressed. For example, October CMS 3.0 initially required Laravel 8.x, while later 3.x releases moved to Laravel 9.x. Knowing the exact target version for your specific October CMS release is crucial. You’ll find this information in the composer.json of the October CMS skeleton or in the official upgrade documentation.

3. Check Plugin and Theme Compatibility

This is the most common point of failure — we’ve seen many upgrade attempts stymied by incompatible plugins. Verify that all your installed plugins and your active theme are compatible with the target versions of both October CMS and Laravel. Here’s how:

  • Check the October CMS marketplace listing for each plugin; look for version compatibility information.
  • Visit the plugin’s GitHub repository and review the composer.json constraints.
  • Contact the plugin developers directly if compatibility isn’t clear.
  • For maintained plugins, you’ll often see something like "october/rain": "^1.30" or "illuminate/support": "^9.0" which indicates Laravel 9.x compatibility.
  • If a plugin hasn’t been updated in years and shows no signs of maintenance, you may need to look for alternatives or be prepared to fix compatibility issues yourself.

One may wonder: what if a critical plugin isn’t compatible? You have a few options: fork the plugin and update it yourself (if the codebase is small), contact the developer to request an update, replace the plugin with an alternative, or delay your upgrade until compatibility is resolved. There’s no universal answer — it depends on your specific dependencies.

4. Check System Requirements

Ensure your server environment meets the requirements for the target Laravel version. Pay close attention to:

  • PHP version: October CMS 3.x typically requires PHP 8.0.2 or higher; October CMS 2.x may run on PHP 7.2.9 or higher. Verify your server’s PHP version with php -v or php --version.
  • PHP extensions: Laravel requires several extensions such as openssl, pdo, mbstring, tokenizer, xml, curl, bcmath, and gd or imagick. Your target Laravel version may add new requirements.
  • Composer version: Ensure you’re running a recent Composer version (2.x). Older Composer 1.x may have issues with newer packages.

You can check your current PHP extensions with php -m. If you’re missing required extensions, you’ll need to install them before proceeding. On Ubuntu/Debian, for example, you might run: sudo apt-get install php8.1-mbstring php8.1-xml php8.1-curl php8.1-bcmath (adjust for your PHP version).

Step-by-Step Upgrade Guide

With preparations complete, we can begin the upgrade process. We’ll walk through each step methodically.

Safety First: Version Control Reminder

Before we proceed, a word about safety. If you’re using Git (which we strongly recommend), ensure that your current working state is committed and pushed to a remote repository. This gives you a safe rollback point. If you’re not using version control, now would be an excellent time to initialize a repository before proceeding:

$ git init
$ git add .
$ git commit -m "pre-upgrade backup"

Honestly, we cannot overstate the value of version control for operations like this. It’s not just about tracking changes — it’s about having a reliable way to revert if something goes wrong.

1. Enable Maintenance Mode

First, put your application into maintenance mode to prevent users from accessing it during the upgrade. This is especially important for production sites, but even in development it provides a clear visual indicator that work is in progress.

Usage

php artisan down [options]

In its simplest form, we simply run:

$ php artisan down
Application In Maintenance Mode!

You should see the confirmation message shown above. If you navigate to your site in a browser, you’ll see the default maintenance page (or your custom one if you’ve configured it).

The down command affects all routes by default, which is usually what you want. One may wonder: what about API endpoints? They are also blocked by default — which is appropriate during maintenance, as you typically don’t want any public access while making structural changes. The down command supports several options; for completeness:

$ php artisan down --help
Usage:
  artisan down [options]

Options:
      --allow[=ALLOWED_IPS]        IPs or hostnames allowed to access the application while in maintenance mode (supports comma-separated values)
      --render[=VIEW]              The view to render for maintenance mode (default: errors::maintenance)
      --redirect[=REDIRECT]        URL to redirect all maintenance requests to
      --refresh[=SECONDS]          The number of seconds after which the maintenance mode will be automatically refreshed (default: 60)
      --status[=CODE]              The HTTP status code to return when in maintenance mode (default: 503)
      --retry-after[=SECONDS]      The number of seconds after which the request may be retried (default: refresh value)
      --secret[=SECRET]            The secret used to bypass maintenance mode (see artisan up --secret)
  -h, --help                       Display this help message
      --version                    Display this application version

For a typical upgrade, the simple form with no options is sufficient. When you’re ready to bring the site back up, we’ll run php artisan up later. Note that down is conservative — it only sets a flag in the storage/framework/down file and doesn’t modify any other state. This means it’s safe to run even if the application is already in maintenance mode; it simply overwrites the existing flag.

2. Update composer.json

The core of the upgrade is modifying your composer.json file. You will need to update the version constraints for october/all and any other packages that depend on it. Let’s be precise about what to change.

First, open your composer.json file in a text editor. You’ll see a require section that likely looks something like this if you’re on October CMS 2.x:

"require": {
    "php": "^7.2.9",
    "october/all": "^2.0"
},

Or if you’re on an earlier October CMS 3.x version:

"require": {
    "php": "^8.0.2",
    "october/all": "^3.1"
},

To upgrade to October CMS 3.2.x (which as of March 2026 is the current stable release and uses Laravel 9.x), you would change it to:

"require": {
    "php": "^8.0.2",
    "october/all": "^3.2"
},

Note the subtle differences: the PHP version constraint changes from ^7.2.9 to ^8.0.2 — that’s because October CMS 3.x requires PHP 8.0.2 or higher. The october/all constraint moves from ^2.0 to ^3.2, which will pull in the appropriate Laravel 9.x components.

What about explicitly specifying Laravel? You generally don’t need to add laravel/framework to your composer.json manually when using october/all. The October CMS package already requires the correct Laravel version as a dependency. However, if you need to override or pin to a specific Laravel version for some reason, you could add it explicitly:

"require": {
    "php": "^8.0.2",
    "laravel/framework": "^9.52",
    "october/all": "^3.2"
},

We recommend against this unless you have a specific need — it’s better to let October CMS manage the Laravel version through its tested constraints. Though there may be edge cases where you need a specific Laravel patch version for security reasons, these are rare.

3. Run Composer Update

With the composer.json file updated, it’s time to let Composer resolve and install the new dependencies.

Usage

composer update [--options] [package...]

The simplest form updates all dependencies according to your composer.json:

$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev) from lock file
Package operations: 45 installs, 12 updates, 0 removals
  - Downloading illuminate/contracts (v9.52.3)
  - Downloading illuminate/support (v9.52.3)
  - Downloading october/all (v3.2.0)
  - ...
  Writing lock file
  Installing dependencies from lock file (including optimize-dev autoloader)

This command does three things:

  1. Resolves dependencies — calculates the exact versions that satisfy all constraints.
  2. Updates composer.lock — writes the resolved versions to the lock file.
  3. Installs packages — downloads and places files in the vendor/ directory.

Verbosity and Monitoring

We recommend running with at least -v (verbose) to see what’s happening:

$ composer update -v

Use -vvv for maximum detail if troubleshooting:

$ composer update -vvv

Targeted Updates

You can update only specific packages:

$ composer update october/all

This updates only the october/all package and its direct dependencies, leaving other packages at their locked versions. This is safer when you want to limit the scope of changes.

However, for major version jumps (e.g., October CMS 2.x to 3.x), you’ll often need to update all dependencies because the entire ecosystem shifts. In these cases, omitting package names — running composer update without arguments — is appropriate.

Memory Limits

Composer can consume substantial memory for large dependency trees. If you encounter memory exhaustion errors:

$ COMPOSER_MEMORY_LIMIT=-1 composer update

The -1 value removes the memory cap entirely. Alternatively, set a specific limit:

$ COMPOSER_MEMORY_LIMIT=2G composer update

Use these judiciously on systems with sufficient RAM. On memory-constrained servers, you might need to upgrade the system memory or use a swap file rather than removing limits entirely.

Understanding Composer’s Behavior

Composer’s default behavior is conservative: it tries to keep all package versions within their previously established constraints from composer.lock unless version constraints in composer.json explicitly require changes. This is usually what you want — it minimizes unexpected version changes.

However, when you change major version constraints (e.g., "october/all": "^2.0" to "october/all": "^3.2"), you’re signaling that you want the newer versions. One may wonder: what about indirect dependencies? Packages that your direct dependencies rely on may have their own constraints. Composer handles this automatically, but conflicts can arise. We’ll cover troubleshooting in a later section.

Safety Note Before Update

Before running composer update, ensure your current state is safely committed to version control. The update makes substantial changes to composer.lock and vendor/. If something goes wrong, you’ll want to be able to restore the previous state quickly:

$ git add composer.json composer.lock
$ git commit -m "Prepare for upgrade: updated october/all constraint to ^3.2"

This gives you a rollback point. If you’re not using version control, now is an excellent time to start — see the Safety First section earlier.

Post-Upgrade Checklist

Once Composer has finished, a few crucial steps remain. We’ll walk through them systematically.

1. Clear All Caches

You’ll want to clear all relevant caches to ensure the application loads the new framework files correctly. October CMS’s october:fresh command clears multiple caches in one operation.

Usage

php artisan october:fresh [options]

The simplest form:

$ php artisan october:fresh
Application cache cleared!
Configuration cache cleared!
Route cache cleared!
...

The output indicates which caches were cleared. Under the hood, october:fresh combines several Laravel cache-clearing operations:

  • Configuration cache (config:clear)
  • Route cache (route:clear)
  • View cache (view:clear)
  • October CMS’s own cache

You may ask: why run additional individual commands if october:fresh already does most of them? The answer is redundancy for safety — we’ve seen cases where a stale cache file survives a fresh install, particularly if you have custom cache stores or optimized configs. Running them individually ensures nothing is missed. The extra few seconds are worth the certainty.

After october:fresh, you can explicitly verify caches are clear by running:

$ php artisan config:clear
$ php artisan route:clear
$ php artisan view:clear

The october:fresh command is idempotent — it’s safe to run multiple times without side effects. If you’re unsure whether caches were fully cleared, running it again won’t harm anything.

2. Run Database Migrations

The upgrade may include database schema changes. October CMS manages its own migrations through the october:up command. Run it to apply any necessary database updates.

Usage

php artisan october:up [options]

In the typical case:

$ php artisan october:up
Migrating: 2024_01_15_000000_create_new_table
Migrated:  2024_01_15_000000_create_new_table (0.15 seconds)

You should see output indicating which migrations ran. If you see “Nothing to migrate,” that’s also a successful outcome — it means the database schema is already up to date.

Options and Safety

Before running migrations on production, it’s wise to preview what will happen:

$ php artisan october:up --pretend

The --pretend flag shows which migrations would run without actually executing them. This is read-only and safe to run at any time.

The october:up command does not have a built-in rollback mechanism — unlike Laravel’s migrate:rollback. October CMS migrates forward only. One may wonder: what if migrations fail partway through? That’s why your database backup from the pre-upgrade checklist is essential. Should you need to revert:

  1. Restore the database from your SQL dump.
  2. Ensure your code is at the pre-upgrade state (via version control).
  3. Run php artisan october:fresh to clear any cached schema information.

Migrations can fail for several reasons:

  • Plugin compatibility issues (a plugin’s migration expects columns or tables that don’t match the new schema).
  • Database permission problems.
  • Missing PHP extensions that affect database drivers.
  • Insufficient disk space.

If a migration fails, check storage/logs/laravel.log for the specific error. Often the issue is a plugin that needs updating or database constraints that have changed between Laravel versions.

The october:up command is not verbose by default; if you need more detail, increase verbosity:

$ php artisan october:up -vvv

This shows each migration file being processed along with extended diagnostic information. However, note that -vvv can produce substantial output for large applications with many plugins.

3. Thoroughly Test Everything

This is a critical final step — do not skip it. We recommend systematic testing in this order:

Frontend Testing:

  • Visit your homepage and key landing pages to ensure they load without errors.
  • Test forms (contact forms, search forms, comment forms) to verify submissions work.
  • Check that all static pages render correctly, including any custom templates.
  • Test responsive design on different screen sizes if your theme is responsive.

Backend Testing:

  • Log into the October CMS backend (/backend or your custom URL) with an admin account.
  • Navigate through the backend menu to ensure all sections load.
  • Test the CMS section: edit pages, save changes, preview.
  • Test the Media section: upload images, browse media library.
  • Test the Settings section: modify system settings and save.
  • Test any plugin-specific backend interfaces (lists, forms, reports).

Authentication Testing:

  • Test user registration (if enabled) and verify confirmation emails if applicable.
  • Test login and logout flows.
  • Test password reset functionality.
  • Verify that user roles and permissions are enforced correctly (e.g., only admins can access backend).

Plugin and Custom Code:

  • Activate any plugins that were deactivated before upgrade (if you had to disable them).
  • Test each plugin’s frontend and backend features thoroughly.
  • Review any custom code you have (custom plugins, theme modifications, bespoke modules) for compatibility issues.

Log Review:

Throughout testing, keep an eye on the Laravel log file:

$ tail -f storage/logs/laravel.log

This will show you any exceptions, deprecation warnings, or errors in real time. Of course, you should address any errors you find before considering the upgrade complete.

4. Disable Maintenance Mode

Usage: php artisan up [options]

Once you are confident that the upgrade was successful and the site is stable, bring your application back online:

$ php artisan up
Application is live!

After running this command, verify that your site is accessible from a browser. If you still see the maintenance page, clear your browser cache or check if you have a custom maintenance template that needs updating.

Troubleshooting Common Issues

Even with careful preparation, you may encounter issues during the upgrade process. We’ve seen most of these before; let’s walk through common problems and their solutions.

Composer Reports “Nothing to update or install”

You’ve updated your composer.json but Composer insists there’s nothing to install. This usually means Composer’s cache or lock file is interfering. Here’s what to try:

  1. Clear Composer’s cache: Sometimes Composer’s package metadata cache is stale. Run:

    $ composer clear-cache

    Then try composer update again.

  2. Delete the lock file: The composer.lock file locks your dependencies to specific versions. If you’re changing version constraints significantly (e.g., from October CMS 2.x to 3.x), you may need to start fresh:

    $ rm composer.lock
    $ composer update

    Of course, make sure your composer.lock is committed to version control before deleting it, so you can restore it if needed.

  3. Use --with-all-dependencies: This flag tells Composer to consider all dependencies, not just direct ones, when resolving versions:

    $ composer update october/all --with-all-dependencies

    The --with-all-dependencies flag (or -W) allows Composer to upgrade or downgrade other packages as needed to satisfy constraints. This can resolve situations where other packages have locked Laravel components to incompatible versions.

One may wonder: why does this happen? Composer’s dependency resolution is, by default, conservative. It tries to keep all package versions within their previously established constraints unless explicitly told otherwise. The --with-all-dependencies flag loosens that restriction.

Permission Denied Errors

If you encounter permission errors during the upgrade — such as “Permission denied” when writing to vendor/ or storage/ — here’s what to do:

  1. Check your current user: Are you running Composer as the correct user? On production servers, you should typically run Composer as the same user that owns the application files, not as root. Running Composer as root can cause files to be owned by root, which then causes permission problems for your web server. If you’ve accidentally done this, you may need to chown -R www-data:www-data . (adjust www-data to your web server user).

  2. Fix storage and cache permissions: Laravel and October CMS require write access to certain directories:

    $ chmod -R 775 storage bootstrap/cache
    $ chown -R www-data:www-data storage bootstrap/cache  # If needed

    The exact permissions depend on your server setup. On shared hosting, you may need to contact your provider to adjust file permissions, as they often restrict chmod or chown.

  3. Check SELinux or AppArmor: If you’re on a system with SELinux (common on CentOS/RHEL), you might need to set proper contexts:

    $ sudo restorecon -Rv /path/to/your/app

    Though this is less common on Ubuntu/Debian.

Class Not Found Errors After Upgrade

If you see errors like “Class ‘October\Rain\Extension\Extendable’ not found” or “Class ‘Illuminate\Foundation\Application’ not found,” this typically indicates one of three issues:

  1. Autoloader needs regeneration: Run:

    $ composer dump-autoload -o

    The -o flag optimizes the autoloader, which can resolve missing class issues.

  2. Plugin incompatibility: A plugin may be referencing classes that no longer exist in the new Laravel version. Check which plugin is throwing the error from the stack trace. Then:

    • Look for an updated version of that plugin.
    • Temporarily disable the plugin by renaming its directory in plugins/ or using the backend if accessible.
    • Report the issue to the plugin developer.
  3. Incomplete migrations: Sometimes database migrations create or modify models. If these migrations didn’t run, classes might be missing. Re-run:

    $ php artisan october:up
  4. Cache still stale: If you’ve cleared caches already but still see issues, try a more aggressive clear:

    $ rm -rf bootstrap/cache/*.php
    $ rm -rf storage/framework/*

    Then run php artisan october:fresh again.

Plugin Compatibility Issues

When plugins break after an upgrade, we need to systematically isolate and resolve the problem:

  1. Check for updates: Go to the October CMS Marketplace or the plugin’s GitHub repository. Look for version constraints like "october/all": "^3.2" in the plugin’s composer.json. If an update exists, update your composer.json to require the newer version (if the plugin is not part of october/all), then run composer update vendor/plugin-name.

  2. Contact developers: If no update exists but the plugin appears maintained (recent commits, open issues being addressed), reach out to the developer. Many developers are happy to help if they know there’s a compatibility issue.

  3. Isolate the problem: You can determine which plugin is causing the issue by:

    • Disabling all non-essential plugins through the backend (if accessible).
    • If backend is inaccessible, rename plugin directories in plugins/ one by one until the error disappears.
    • Check the error logs for the specific plugin class causing the issue.
  4. Consider alternatives: If a plugin is abandoned (no updates for years, no response to issues), you may need to replace it. Search the marketplace for alternatives with similar functionality that support your target October CMS version.

  5. Fix it yourself: For small plugins, you might be able to fix compatibility issues yourself. Common fixes include:

    • Updating Laravel component references (e.g., Illuminate\Support\Str methods that changed)
    • Adjusting plugin service providers to use new Laravel container bindings
    • Replacing deprecated October CMS APIs with newer equivalents

PHP Version Mismatches

If you encounter PHP version requirement errors like:

Your PHP version (7.4.33) does not satisfy that requirement.

This means your server’s PHP version is too old for the October CMS or Laravel version you’re trying to install. Here’s how to resolve:

  1. Verify your server’s PHP version:

    $ php -v
    PHP 7.4.33 (cli) (built: Oct 25 2023 07:38:36) ...
  2. Check the required PHP version: Review the composer.json of the October CMS version you’re targeting. October CMS 3.x typically requires "php": "^8.0.2" or higher. October CMS 2.x may work with PHP 7.2.9+.

  3. Update your PHP:

    • Ubuntu/Debian:

      $ sudo apt-get install php8.1  # or php8.2, php8.3
      $ sudo update-alternatives --set php /usr/bin/php8.1
    • CentOS/RHEL:

      $ sudo dnf install php81
      $ sudo alternatives --set php /usr/bin/php81
    • macOS with Homebrew:

      $ brew install php@8.2
      $ brew link --overwrite --force php@8.2
    • Windows: Download the appropriate PHP binary from php.net and update your PATH.

  4. Update local development environment: Ensure your local development PHP version matches or exceeds your production PHP version. This prevents developing against features not available in production.

  5. Adjust composer.json if necessary: If your hosting provider only supports an older PHP version and you cannot upgrade, you may need to target an older October CMS version that supports that PHP version. For instance, if you’re stuck on PHP 7.4, you’ll need October CMS 2.x (not 3.x). This is a limitation you’ll need to work within until you can upgrade your hosting environment.

  6. Check php.ini settings: After upgrading PHP, ensure critical settings are configured properly:

    $ php -i | grep -E "(memory_limit|upload_max_filesize|post_max_size|max_execution_time)"
    memory_limit => 128M => 128M
    upload_max_filesize => 2M => 2M
    post_max_size => 8M => 8M
    max_execution_time => 30 => 30

    You may need to increase these for your application, particularly memory_limit for Composer operations.

Verification and Testing

After completing the upgrade, it’s essential to verify that everything is working correctly. We recommend a systematic approach to testing. Let’s break it down.

Before We Begin: The Testing Mindset

First, a word about scope. You might be wondering: how thoroughly should I test? The answer depends on your application’s size and complexity. For a small brochure site, basic smoke tests may suffice. For an enterprise application with custom business logic, custom plugins, and complex integrations, you’ll need comprehensive testing. When in doubt, err on the side of thoroughness. Remember, this is your opportunity to catch issues before they affect users.

We also recommend testing in an environment that closely mirrors your production setup — same PHP version (within reason), same web server (Apache/Nginx), same database version, same cache configuration. Differences between staging and production can mask issues that only appear under real-world conditions.

Creating a Test Plan

We suggest writing down a short test plan before you begin. This doesn’t need to be elaborate — just a checklist of critical user journeys. For example:

  1. Homepage loads without errors
  2. User can register and log in
  3. Contact form submits successfully
  4. Admin can access backend and edit pages
  5. All custom plugin features work
  6. Payment gateway (if applicable) processes transactions
  7. API endpoints return expected responses

Of course, your specific test plan will vary based on your application. The key is to cover all critical paths.

Basic Functionality Tests

Let’s start with fundamental access and navigation:

Frontend Access

Visit your homepage and key landing pages. Look for:

  • HTTP status code 200 (OK), not 500 errors or 404s.
  • No Laravel or PHP error messages displayed.
  • Assets (CSS, JavaScript, images) loading correctly (check browser DevTools Console and Network tabs).
  • Proper HTML rendering (no broken tags or missing content).

We recommend using multiple browsers to catch browser-specific issues. Also test mobile responsiveness if your theme is responsive.

Backend Login

Navigate to your backend URL (typically /backend or /backend/admin). Test:

  • Login with admin credentials succeeds.
  • Dashboard loads without errors.
  • Logout and login again to confirm session handling works.

If you encounter a blank page or error, check storage/logs/laravel.log immediately. Authentication issues often relate to session configuration or encryption key mismatches.

Click through all major navigation menus:

  • Frontend menus (main menu, footer links).
  • Backend sidebar menu (all top-level items).
  • Dropdown submenus.

Watch for broken links, missing icons, or JavaScript errors. One may wonder: what if a menu item leads to a 404? That could indicate that a plugin was deactivated or a route wasn’t registered properly. In that case, check that the corresponding plugin is enabled and that you’ve run php artisan october:up to register any new routes.

Database Verification

Let’s ensure your database is intact and migrations are complete:

Migration Status

First, check if any migrations are pending:

$ php artisan october:up --pretend

The --pretend flag shows what migrations would run without actually executing them. You should see either “Nothing to migrate” or a list of migration files that would be applied. If you see pending migrations, run php artisan october:up without --pretend to apply them. Of course, you should already have done this in the Post-Upgrade Checklist, but it’s worth double-checking.

Table Integrity

Connect to your database (via command line or a tool like phpMyAdmin) and verify that all expected tables exist. Look for:

  • Core October CMS tables: system_, backend_, cms_ prefixed tables.
  • Plugin-specific tables (usually with plugin-specific prefixes).
  • All tables from your previous version are still present.

One helpful query:

SHOW TABLES;

Compare the output to a pre-upgrade list if you have one. Missing tables may indicate that a plugin migration didn’t run or that the plugin is incompatible.

Data Consistency

Browse some representative records:

  • CMS pages and content blocks.
  • User accounts (frontend users and backend users).
  • System settings (backend Settings → System settings).
  • Plugin data (e.g., form submissions, product listings if you have a shop plugin).

Look for truncated content, missing relationships, or unexpected NULL values. If you spot issues, they may be related to character set changes (Laravel 9.x defaults to utf8mb4) or column type changes. Check your database collation: SHOW VARIABLES LIKE 'collation%';

Performance Checks

Performance degradation is a common concern after upgrades. Let’s verify that your application remains performant.

Response Time

Use tools like:

  • Browser DevTools Network tab.
  • curl -w "@curl-format.txt" -o /dev/null -s https://yoursite.com
  • External services like WebPageTest or GTmetrix.

Compare key page load times to your pre-upgrade baseline. A slight increase (10 - 20%) may be acceptable, but larger degradations warrant investigation. Common causes:

  • Missing cache (you cleared caches, but have you rebuilt them?).
  • Inefficient queries introduced by new plugin versions.
  • Autoloader issues (run composer dump-autoload -o to optimize).

Memory Usage

Monitor PHP memory usage. Laravel’s memory footprint can vary between versions. You can check peak memory usage by adding a simple test script or using Laravel Debugbar. If you see memory exhaustion errors (Allowed memory size of X bytes exhausted), you may need to increase memory_limit in php.ini or optimize your application’s memory usage.

Database Queries

If you have Laravel Debugbar or Clockwork installed, use them to examine query counts and execution times. Look for:

  • N+1 query problems (common after upgradingEloquent relationships).
  • Slow queries that weren’t slow before.
  • Unexpected duplicate queries.

If you identify issues, consider adding eager loading (with()) or caching query results. Of course, these optimizations are beyond the scope of this guide, but we mention them for completeness.

Plugin and Theme Validation

Now let’s systematically verify your plugins and theme.

Plugin Functionality

Go through each installed plugin and test its features:

  • Does the plugin’s backend interface load without errors?
  • Does the plugin’s frontend components render correctly?
  • Can you create, edit, and delete records through the plugin?
  • Do scheduled tasks (if any) run correctly? Check storage/logs/laravel.log for task output.
  • Do notifications and events fire as expected?

For each plugin, we recommend checking the plugin’s own documentation for version-specific changes. Some plugins may have breaking changes between versions that require configuration updates.

Theme Compatibility

Test your theme thoroughly:

  • All page templates render correctly.
  • Partial templates (headers, footers, sidebars) display properly.
  • Custom components (if using October CMS components) work as expected.
  • Asset files (CSS, JavaScript, images) load with correct paths.
  • If your theme uses Laravel Mix or other build tools, run your build process (npm run dev or npm run prod) to ensure assets are up to date.

One may wonder: what if my theme breaks? Many themes rely on specific October CMS APIs that may have changed. Check the theme’s theme.yaml for compatibility requirements. If the theme is custom-built by your team, you’ll need to review your code for deprecated methods and update accordingly.

Custom Code

Review any custom plugins, modules, or theme modifications you’ve made:

  • Custom service providers: Do they register correctly without errors?
  • Custom models: DoEloquent queries work? Are relationships intact?
  • Custom commands: Can they be executed via php artisan?
  • Custom middleware: Does it execute without errors?
  • Custom Twig filters or functions: Do they work in templates?

Pay special attention to any code that uses:

  • Laravel facades that may have moved namespaces.
  • October CMS classes that have been deprecated (check deprecation notices in storage/logs/laravel.log).
  • Third-party packages that may have breaking changes in their new versions.

Security Verification

Security is paramount. Let’s verify that security mechanisms remain intact.

Permissions

Test user roles and permissions:

  • Regular users cannot access backend /backend URL.
  • Users with specific roles can only see menu items they’re permitted to view.
  • Form submissions respect permission checks (e.g., only admins can delete records).
  • API tokens (if using Laravel Sanctum or Passport) still function.

Try accessing a backend route as a non-admin user — you should see a 403 Forbidden or be redirected to login.

File Access

Ensure that protected files are not directly accessible via URL:

  • storage/app/ should not be web-accessible.
  • .env file should not be accessible.
  • Private uploads (if stored in storage) should require authentication to access.

You can test by attempting to access these paths directly in a browser. If you can download .env or view files from storage/app/, you have a serious security misconfiguration that needs immediate attention.

CSRF Protection

Test forms that should have CSRF protection:

  • Submitting a form without a valid CSRF token should fail (403 error).
  • Submitting a valid form should succeed.

Check that your forms include {{ csrf_field() }} or @csrf directives if you’re using Blade templates in your theme. October CMS’s form framework usually handles this automatically, but custom forms may need attention.

Automated Testing

If you have automated tests in place, now is the time to run them:

  • Unit Tests: Test individual classes and methods.

    $ vendor/bin/phpunit --testsuite=Unit
  • Feature Tests: Test full request/response cycles.

    $ vendor/bin/phpunit --testsuite=Feature
  • Integration Tests: Test interactions between multiple components.

Pay special attention to any tests that fail. A failing test may indicate a breaking change you need to address. Don’t just silence failing tests — fix the underlying issue. Of course, if your test suite hasn’t been updated for the new Laravel version, you may need to update test scaffolding or mocks.

The Final Verification Checklist

Before considering your upgrade complete, ensure you’ve covered:

  • Frontend pages render correctly (no 500 errors, proper styling)
  • Backend login works and dashboard loads
  • All critical user workflows function (registration, login, content creation, etc.)
  • All plugin features tested and working
  • Database migrations applied successfully
  • No errors in storage/logs/laravel.log during testing period
  • Performance acceptable compared to pre-upgrade baseline
  • Security checks passed (permissions, file access, CSRF)
  • Automated test suite passes (if applicable)
  • Maintenance mode disabled with php artisan up

If any of these items are unchecked, investigate and resolve before declaring the upgrade complete — especially if you’re on a production site.

Complete Walkthrough: Upgrading from October CMS 2.x to 3.x

Let’s walk through a concrete upgrade scenario to cement these concepts. We’ll upgrade a hypothetical October CMS 2.0 application (running Laravel 5.5) to October CMS 3.2 (running Laravel 9.x). This is a substantial jump — it involves upgrading PHP versions and dealing with significant API changes — but it illustrates the full process.

Important: This walkthrough assumes a development environment. Do not run these commands on production without testing first.

Step 1: Assess the Starting Point

Before making any changes, let’s establish a comprehensive baseline. We’ll capture the current state of the system so we can verify changes later and troubleshoot if needed.

First, the PHP version:

$ php -v
PHP 7.2.34 (cli) (built: Oct 12 2022 06:16:22) ...

Next, the October CMS and Laravel versions:

$ php artisan --version
Laravel Framework 5.5.40
October CMS 2.0.13

Now, let’s examine the composer.json more completely. The grep approach shows only part of the file; let’s view the entire require section plus any platform requirements:

$ cat composer.json | jq '.require'  # if you have jq installed
{
  "php": "^7.2.9",
  "october/all": "^2.0"
}

If you don’t have jq (a JSON processor), you can use php to parse it:

$ php -r "echo json_encode(json_decode(file_get_contents('composer.json'))->require, JSON_PRETTY_PRINT);"

Or simply open composer.json in an editor and note the entire require and require-dev sections. For our walkthrough, we’ll assume:

{
    "require": {
        "php": "^7.2.9",
        "october/all": "^2.0"
    }
}

We can also capture the current dependency list from composer.lock. To see the installed Laravel components specifically:

$ composer show | grep illuminate
illuminate/auth              v5.5.43  The Illuminate Auth package.
illuminate/broadcasting      v5.5.43  The Illuminate Broadcasting package.
illuminate/bus               v5.5.43  The Illuminate Bus package.
...

Or extract just the Laravel framework version from the lock file:

$ composer show laravel/framework
name     : laravel/framework
descrip. : The Laravel Framework.
keywords : framework, laravel
versions : * v5.5.43
type     : library
license  : MIT
source   : [git] https://github.com/laravel/framework.git
dist     : [zip] https://api.github.com/repos/laravel/framework/zipball/v5.5.43

The version shown (v5.5.43) is the exact installed version.

We also need to inventory installed plugins. Using October CMS’s Artisan command:

$ php artisan plugin:list
+----------------------+----------+----------------------+---------+
| Plugin               | Version  | Code                 | Enabled |
+----------------------+----------+----------------------+---------+
| RainLab.User         | 2.10.4   | RainLab.User         | Yes     |
| RainLab.Builder      | 2.0.7    | RainLab.Builder      | Yes     |
| ...                  | ...      | ...                  | ...     |
+----------------------+----------+----------------------+---------+

Record this list; we’ll need to verify each plugin remains compatible after the upgrade.

Baseline Check Summary

We’ve now established:

  • PHP version: 7.2.34
  • Laravel version: 5.5.43
  • October CMS version: 2.0.13
  • Composer constraints: "php": "^7.2.9", "october/all": "^2.0"
  • Installed plugins: [list from above]

We can see clearly:

  • PHP 7.2.34 (October CMS 2.x runs on PHP 7.2.9+, but October CMS 3.x requires PHP 8.0.2+).
  • October CMS 2.0 with Laravel 5.5.
  • We’ll need to upgrade PHP, October CMS, and Laravel — but the order matters. We upgrade PHP first, then October CMS through Composer.

One may wonder: could we skip recording the plugin list? No — we’ll need it to identify plugin compatibility issues later. Document this in your upgrade notes.

Step 2: Prepare and Back Up

Before anything else, let’s commit our current state to version control (if not already):

$ git add .
$ git commit -m "pre-upgrade-october-2-to-3"

And create a database backup:

$ mysqldump -u root -p myapp_db > backup-october-2-$(date +%Y%m%d).sql

Now, let’s ensure we have a staging environment that matches production. Since we’re upgrading from PHP 7.2 to PHP 8.1 (we’ll choose 8.1 as it’s well-supported), we’ll need to install PHP 8.1 first:

On Ubuntu:

$ sudo apt-get install php8.1 php8.1-cli php8.1-common php8.1-curl php8.1-mbstring php8.1-xml php8.1-zip php8.1-bcmath php8.1-gd

On macOS with Homebrew:

$ brew install php@8.1
$ brew link --overwrite --force php@8.1

After installing, verify:

$ php -v
PHP 8.1.2 (cli) (built: Feb 17 2023 16:57:09) ...

Of course, make sure your web server is also using PHP 8.1, but for the Composer upgrade we just need CLI PHP to be updated.

Step 3: Update composer.json

Now, update your composer.json. Change the require section:

"require": {
    "php": "^8.0.2",
    "october/all": "^3.2"
},

Remove any explicit Laravel framework constraints if present — let october/all manage it.

One may wonder: what about other packages? Check your composer.json for any packages that might conflict with Laravel 9.x. Common culprits are packages that require older illuminate/* components. You may need to update or replace them.

Step 4: Enable Maintenance Mode

$ php artisan down
Application In Maintenance Mode!

Step 5: Run Composer Update

Now run the update:

$ COMPOSER_MEMORY_LIMIT=-1 composer update -vvv

The -vvv flag gives very verbose output, which is helpful if something goes wrong.

You’ll see a long list of packages being downloaded and updated. The output might look like:

Loading composer repositories with package information
Updating dependencies (including require-dev) from lock file
Package operations: 0 installs, 68 updates, 5 removals
  - Updating illuminate/support (v5.5.43 => v9.52.3)
  - Updating illuminate/contracts (v5.5.43 => v9.52.3)
  - Updating october/all (2.0.13 => 3.2.0)
  - Updating october/rain (1.30.5 => 1.32.0)
  - Removing illuminate/routing (5.5.43)
...
Writing lock file
Installing dependencies from lock file (including optimize-dev autoloader)
...

The process may take several minutes. If you encounter errors, read them carefully — they often tell you exactly which package is causing the conflict.

Verifying the Update

After Composer finishes successfully, let’s inspect what changed. This serves both as verification and as practice for understanding your system.

First, compare the Laravel framework version:

$ composer show laravel/framework
name     : laravel/framework
descrip. : The Laravel Framework.
versions : * v9.52.3

Compared to the baseline of v5.5.43, we’ve successfully moved to Laravel 9.52.3. The exact patch version may differ — what matters is the major version is now 9.

We can also examine the october/all package:

$ composer show october/all
name     : october/all
descrip. : October CMS - All
versions : * v3.2.0

Notice the version moved from 2.0.13 to 3.2.0. This single package constraint pulled in all the necessary Laravel components and October CMS modules.

To get a summary of the overall change, count the packages before and after:

$ composer show | wc -l  # number of installed packages

Before the upgrade, you might have had around 100-150 packages (depending on plugins). After, the count will likely be different — not just due to Laravel version changes, but also plugin updates that may have added or removed dependencies.

Inspect the composer.lock file: it now contains the exact versions installed. You can examine specific Laravel component versions:

$ grep -E "illuminate/|laravel/framework" composer.lock | head -20

This shows the installed versions of all illuminate/* packages and laravel/framework. They should all be in the 9.x range now.

Finally, verify the autoloader was optimized by Composer:

$ ls -la vendor/composer/autoload_*.php

You should see several autoload files including autoload_classmap.php, autoload_static.php, etc. The presence of these files indicates the autoloader is ready. If you see corruption or missing files, run:

$ composer dump-autoload -o

This regenerates the optimized autoloader.

Troubleshooting Update Failures

If Composer fails, the error message usually indicates the conflict. Example:

Problem 1
    - illuminate/support[v9.0.0, ..., 9.x-dev] require illuminate/contracts ^9.0 -> satisfied by illuminate/contracts[9.0.0, ..., 9.x-dev].
    - Root composer.json requires illuminate/support ^5.5 -> satisfiable by illuminate/support[5.5.0, ..., 5.5.x-dev].

This type of error suggests your composer.json still has a constraint requiring an old illuminate/support version. You must find where that constraint originates — it could be a plugin’s composer.json directly, or a plugin that hasn’t been updated to be compatible with Laravel 9.

To identify the source:

$ composer why-not illuminate/support ^9.0

This tells you which package(s) are preventing the installation. You’ll need to either:

  • Update that plugin to a newer version compatible with October CMS 3.x.
  • Replace the plugin with an alternative.
  • Remove the plugin if it’s not essential.
  • As a last resort, fork the plugin and update its constraints manually (if the code itself is compatible).

The --with-all-dependencies flag (shown earlier) can sometimes resolve these by allowing Composer to update multiple packages simultaneously, but it won’t override fundamental incompatibilities. Use it when you see dependency conflicts that seem resolvable by updating more packages together:

$ composer update october/all --with-all-dependencies

This tells Composer it may update any package in the tree, not just the one you named, to satisfy constraints. Again, though, if a plugin truly requires an older Laravel version that doesn’t exist in the new major release, no flag will fix it — you must address the plugin itself.

With our update verified successful, we can proceed.

Step 6: Clear Caches and Run Migrations

After Composer finishes successfully:

$ php artisan october:fresh
$ php artisan october:up

The october:up command will apply any database migrations needed for October CMS 3.x. You should see output like:

Migrating: 2021_10_01_000000_create_cms_theme_params_table
Migrated:  2021_10_01_000000_create_cms_theme_params_table (0.12 seconds)
...

If you see migration errors, note them. Some plugins may have migrations that fail under the new version. You may need to update those plugins or manually adjust the database.

Verifying Caches and Migrations

After clearing caches and running migrations, verify the results.

First, check that cache files were actually removed:

$ ls bootstrap/cache/
# Should show: config.php (if exists) and services.php (if present)
# Should NOT show: config.php.bak, routes.php, or old compiled views

The bootstrap/cache directory typically contains:

  • config.php — if you ever ran php artisan config:cache
  • services.php — if you ever ran php artisan optimize

If you see these files and wanted a completely fresh start, you can remove them manually:

$ rm -f bootstrap/cache/config.php bootstrap/cache/services.php

Next, check the storage caches:

$ ls storage/framework/
# Should contain: cache/, sessions/, testing/, views/

The cache/, sessions/, and views/ subdirectories should exist but should not contain old cache files from the previous version. You can safely remove any .php files in storage/framework/ if you suspect stale data:

$ rm -f storage/framework/*.php

However, be careful not to delete entire subdirectories — sessions/ holds active user sessions. Of course, forcing all users to log out may be acceptable during a maintenance window; still, be aware of the impact.

Now verify migrations actually ran. Check the database’s migrations table:

SELECT * FROM system_plugins;  -- October CMS tracks plugin migrations
SELECT * FROM migrations;       -- If using Laravel's migration table (some plugins)

Or more directly, use October CMS’s Artisan command to check pending migrations:

$ php artisan october:up --pretend

If it says “Nothing to migrate,” the database is up to date. If it lists migrations, run php artisan october:up again to apply them.

You can also verify the database schema matches expectations. For a specific plugin table, describe it:

$ mysql -u root -p -e "DESCRIBE myapp_db.rainlab_user_users;"

Check that columns exist as expected and data types are correct for the new version. Migration errors often manifest as missing columns or wrong column types. If you spot issues, consult the plugin’s migration file in plugins/rainlab/user/updates/ (for example) to see what schema changes are expected.

One may wonder: what about October CMS’s own core schema? The october:up command applies core migrations stored in the modules/system/updates/ directory. You can list what’s been applied by checking the system_plugins table for the System plugin version and migration status. Strictly speaking, October CMS doesn’t use a dedicated migrations table like Laravel; it tracks applied updates in the system_plugins table’s version and is_system fields.

Finally, confirm the October CMS version in the database matches the code:

$ php artisan october:info

This should report the current version as 3.2.x (or whatever you upgraded to). If it still shows the old version, clear caches again — sometimes the version is cached.

With caches confirmed clear and migrations applied, we’re ready for testing.

Now verify migrations actually ran. Check the database’s migrations table:

SELECT * FROM system_plugins;  -- October CMS tracks plugin migrations
SELECT * FROM migrations;       -- If using Laravel's migration table (some plugins)

Or more directly, use October CMS’s Artisan command to check pending migrations:

$ php artisan october:up --pretend

If it says “Nothing to migrate,” the database is up to date. If it lists migrations, run php artisan october:up again to apply them.

You can also verify the database schema matches expectations. For a specific plugin table, describe it:

$ mysql -u root -p -e "DESCRIBE myapp_db.rainlab_user_users;"

Check that columns exist as expected and data types are correct for the new version. Migration errors often manifest as missing columns or wrong column types. If you spot issues, consult the plugin’s migration file in plugins/rainlab/user/updates/ (for example) to see what schema changes are expected.

One may wonder: what about October CMS’s own core schema? The october:up command applies core migrations stored in the modules/system/updates/ directory. You can list what’s been applied by checking the system_plugins table for the System plugin version and migration status.

Finally, confirm the October CMS version in the database matches the code:

$ php artisan october:info

This should report the current version as 3.2.x (or whatever you upgraded to). If it still shows the old version, clear caches again — sometimes the version is cached.

With caches confirmed clear and migrations applied, we’re ready for testing.

Step 7: Test Thoroughly

Now, let’s test:

$ php artisan up

Visit your site. What do you see?

Scenario A (Success): Pages load, backend accessible, everything works. Excellent! Continue with full testing per our checklist.

Scenario B (White screen/500 error): Check storage/logs/laravel.log. Common issues:

  • Missing PHP extensions (install them).
  • Class not found errors (clear caches again: php artisan cache:clear and composer dump-autoload -o).
  • Database connection issues (check .env database credentials).

Scenario C (Theme doesn’t render): October CMS 3.x introduced Twig namespace changes. In your theme’s pages/ and partials/ templates, you may need to update {% partial "..." %} to use fully qualified paths or adjust namespaces. Check the October CMS upgrade guide for specific theme migration steps.

Scenario D (Plugins broken): Look for deprecation warnings in logs. You may need to update plugins to versions compatible with October CMS 3.x. If a plugin hasn’t been updated in years, you may need to replace it.

Let’s assume we’re in Scenario A and everything appears to work. Now test systematically:

  • Log into backend (/backend).
  • Edit a CMS page and save.
  • Test the contact form.
  • Check the Media manager.
  • Test any e-commerce or form plugin features.

Step 8: Check Logs and Profiler

Keep an eye on the logs while testing:

$ tail -f storage/logs/laravel.log

Also, if you have Laravel Debugbar installed, look for:

  • Deprecation warnings (these indicate code that will break in future versions).
  • Slow queries.
  • High memory usage.

Address any issues you find before declaring victory.

Step 9: Review and Commit

Once all testing passes, commit your changes:

$ git add .
$ git commit -m "Upgrade October CMS 2.x to 3.2 (Laravel 5.5 to 9.x)

- Update composer.json: october/all ^2.0 -> ^3.2
- Upgrade PHP from 7.2 to 8.1
- Run database migrations
- Clear all caches
- Fix theme template paths for new Twig namespaces
- Update plugins: RainLab Newsletter, Author/Plugin to latest compatible versions"

Include a detailed commit message that documents what changed and why. This is invaluable for future maintenance.

Step 10: Deploy to Production

When you’re satisfied that the upgrade is complete and stable on your staging environment, you can deploy to production. The deployment steps mirror what we did in staging:

  1. Deploy code (git pull, copy files, etc.)
  2. Run composer install --no-dev --optimize-autoloader
  3. Run php artisan october:fresh
  4. Run php artisan october:up
  5. Clear any additional caches (Redis, Memcached, Cloudflare, etc.)
  6. Disable maintenance mode: php artisan up
  7. Smoke test production immediately.

One final note: Keep your old code and database backup for at least one full release cycle. Should a critical issue surface that you didn’t catch in testing, you’ll want the ability to roll back quickly.

Walkthrough Recap: What We Learned

This walkthrough demonstrated:

  • The importance of aligning PHP, October CMS, and Laravel versions.
  • The step-by-step sequence: backup → composer.json update → composer update → caches → migrations → testing.
  • Common failure points: PHP version mismatches, plugin incompatibility, theme Twig changes.
  • The value of verbose output and log checking during upgrade.
  • The necessity of thorough testing before production deployment.

Of course, your specific upgrade path may differ — you might be upgrading within October CMS 3.x (e.g., 3.1 to 3.2) which is far simpler and doesn’t require PHP upgrades. But the principles are the same: understand constraints, prepare carefully, execute methodically, verify thoroughly.

Alternative Approaches and Considerations

While the standard October CMS upgrade path — updating october/all and its dependencies — works for most users, you might be wondering: are there other options? Let’s explore the alternatives and when they make sense.

Migrating to Vanilla Laravel

One approach that some teams consider is migrating from October CMS to a vanilla Laravel application. This is a significant undertaking — effectively rebuilding your application on Laravel without October CMS’s CMS features — but it may be appropriate if:

  • You’ve outgrown October CMS’s CMS capabilities and need more custom control.
  • Your application is more of a web application than a content-managed site.
  • You want to reduce dependencies and simplify your stack.
  • You’re willing to rebuild frontend management interfaces.

The migration process would involve:

  • Setting up a new Laravel project.
  • Recreating database tables and models.
  • Porting over business logic from plugins into Laravel services or packages.
  • Replacing October CMS’s frontend rendering with Laravel Blade or another templating system.
  • Building admin interfaces with Laravel Nova, Filament, or custom solutions.

Of course, this is a major project that could take weeks or months depending on your application’s size. It’s not an “upgrade” but a rewrite. For most October CMS users, staying within the October ecosystem is the pragmatic choice.

Forking and Customizing October CMS

At the opposite extreme, some teams choose to fork the October CMS core and maintain their own custom version with specific Laravel versions or modifications. This is an advanced approach suitable only for:

  • Large organizations with dedicated PHP teams.
  • Applications with highly specialized requirements that October CMS doesn’t address.
  • Situations where you need to patchOctober CMS itself rather than wait for upstream changes.

We mention this option not as a recommendation but as an acknowledgment of what exists in the ecosystem. The vast majority of users should not consider this route — it introduces substantial maintenance burden.

Using Direct Laravel Components

Some October CMS users run with a hybrid approach: they keep October CMS for content management but use raw Laravel components for custom features. This is perfectly valid and encouraged. October CMS is built on Laravel, after all — you can access any Laravel service through the Laravel container:

use Illuminate\Cache\CacheManager;

class MyPlugin
{
    public function someMethod()
    {
        $cache = app(CacheManager::class);
        $value = $cache->get('key');
        // ...
    }
}

You might also write standalone Laravel packages (without October CMS dependencies) and include them in your October CMS project via Composer. This allows you to use modern Laravel features even if October CMS hasn’t fully integrated them yet — though, of course, one must be careful not to bypass October CMS’s lifecycle when using raw Laravel components. Some October CMS plugins expect to be able to hook into plugin events and extendable traits. Direct Laravel usage is safest in your own custom plugin code, not inside core plugin modifications.

Rolling Back if Things Go Wrong

We should also discuss the rollback strategy. What if the upgrade introduces unfixable issues? Your options depend on your preparation:

  • From database backup: You can restore the pre-upgrade database dump. However, your code will still be the new version. To fully roll back, you’ll need to:

    1. Restore the database.
    2. Checkout the pre-upgrade code from version control.
    3. Run composer install to get the old vendor dependencies.
    4. Clear caches (php artisan october:fresh).
    5. Bring the site back up.
  • Using database migrations: October CMS doesn’t provide automatic rollback for migrations. If you discover a problem after running migrations, you’ll need to:

    1. Restore the database from backup, OR
    2. Write and run reverse migrations manually (not recommended unless you wrote those migrations yourself and know exactly how to undo them).
  • Feature flags: For large applications, consider deploying the upgraded version behind a feature flag, allowing you to switch back to the old behavior quickly if issues arise. This requires advance planning but can be invaluable for high-stakes upgrades.

One may wonder: can I undo the composer update? Composer doesn’t have an undo command. You could manually revert changes to composer.lock and run composer install, but it’s safer to rely on version control to restore the composer.lock file and vendor/ directory (if you committed it; we generally don’t commit vendor, but some teams do for production stability). The safest approach is to have a tested backup and a clear rollback plan before you upgrade.

When to Upgrade (and When to Wait)

Finally, let’s discuss timing. October CMS follows semantic versioning, and Laravel does too. But does that mean you should upgrade to every new version immediately? Not necessarily.

Consider these factors:

Upgrade when:

  • Your current version has reached end-of-life and no longer receives security patches.
  • A specific new feature or security fix is essential for your application.
  • Your application is in active development and you can absorb the upgrade cost as part of normal maintenance.
  • Your plugins have all been verified compatible with the target version.

Wait when:

  • You’re mid-project with a tight deadline — upgrade as part of post-launch maintenance instead.
  • Critical plugins are not yet compatible with the target version.
  • Your hosting environment cannot support the required PHP version.
  • You lack the development resources to properly test the upgrade.

Our philosophy at Durable Programming is this: upgrade sooner rather than later, but upgrade thoughtfully rather than recklessly. A well-planned upgrade on a regular cadence (e.g., once per year) is far less stressful than playing catch-up after skipping several versions.

The October CMS community generally supports upgrading across one major version at a time. Jumping from October CMS 1.x to 3.x directly is not recommended — go from 1.x to 2.x to 3.x to ensure each step’s migrations and compatibility checks are properly handled. Though, of course, if you’re starting a new project, use the latest stable release.

What About October CMS 4.x and Laravel 10/11?

As of March 2026, October CMS 3.x is the current stable branch with Laravel 9.x support. October CMS 4.x may be in development or early release, potentially targeting Laravel 10.x or 11.x. If you’re reading this in the future and October CMS 4.x is stable, the same principles apply — understand the version matrix, check plugin compatibility, upgrade stepwise, and test thoroughly. The specific version numbers will change, but the approach remains constant.

If you’re considering upgrading directly to a future major release (e.g., October CMS 4.x), we recommend joining the October CMS community forums or Discord to hear about early adopter experiences. Sometimes early major releases have bugs or compatibility gaps that are resolved in subsequent patch releases. Waiting a few months after a major release can save you headaches.

Conclusion

Upgrading the Laravel foundation of your October CMS application is a significant but necessary task to maintain security, performance, and access to modern features. Like elephants navigating the savanna using generational knowledge of water sources, your successful upgrade depends on accumulated wisdom about version compatibility, careful preparation, and systematic testing.

By following the structured approach outlined in this guide — understanding the version relationships, preparing thoroughly, executing the upgrade methodically, and verifying comprehensively — you can confidently move your October CMS application to a newer Laravel version. Remember that the goal isn’t just to chase the latest version numbers, but to ensure your application remains secure, stable, and capable of serving your users’ needs for years to come.

Whether you’re maintaining a small business website or a large enterprise application, investing time in proper upgrade procedures pays dividends in reduced security risks, better performance, and access to the latest features in both Laravel and October CMS ecosystems.

Sponsored by Durable Programming

Need help with your PHP application? Durable Programming specializes in maintaining, upgrading, and securing PHP applications.

Hire Durable Programming