I initially wrote this article when we completed the upgrade and redesign of this site. However, at the time I felt we were so close to seeing a Drupal 7 release that it was somewhat irrelevant and could possibly deter people from getting involved with Drupal 7. After listening to Lullabot Podcast: Drupal 7, Are you ready?, I realized that there are still a number of sites out there that may not be ready to port to Drupal 7, but are in fact built on Drupal 5 which would greatly benefit from moving to Drupal 6 for a number of reasons. Here are just a few:

Basic Background

Many blog posts have been written about this procedure. So here's a quick overview of a process that most of these articles have in common.

The basics require that all D5 modules be updated to their most recent stable release before attempting to upgrade a site to D6. This requires that you confirm that a module has a D6 release or ported to another module (example, bio module was deprecated in favor of content_profile), a process that can be assisted by installing the update_status module. Upon updating your D5 modules you would then put your site off-line and prepare your database for D6 migration by disabling all non-core modules.

At this point, you would clone the D5 database and connect it to your D6 core and module filesystem via settings.php. This is good practice because it leaves your D5 files and database untouched if your update process fails. After core upgrade is completed then modules should be enabled individually along with their dependencies and then update.php needs to run again to get the database updated for that set of modules.

For previous projects, I have usually stuck to this process. Unfortunately, I still fumbled my way through the upgrade having many conflicts along the way which ultimately resulted in data being corrupted. So for Lullabot.com upgrade, I decided to try something new which seemed to have worked very well.

This is where the magic happens

Rather than disabling all non-core modules, I decided to leave existing modules enabled and leverage the select list on update.php to control which modules would be updated during each step. This took a bit of trial and error till I found the best process.

Slightly modifying the preferred method of core files first, I set ALL CCK, Date, Views, and custom modules to be "No updates available" then clicked "Continue". Notice that I left all non-CCK, Date, and Views modules enabled to run their updates on the initial pass. After the 115 or so updates that needed to occur the response was cluttered with errors, but as I read through them they seemed to be non-destructive, just warning messages that certain tables did not exist yet.

After a couple failed next steps, it became apparent that Drupal wanted CCK type modules to be updated next (excluding date, which required CCK core modules to be updated first). So for the next step navigate back to update.php and select CCK related modules to be updated from their D6 update hooks (usually numbered 6000).

Now that CCK base tables have been converted running updates on Date modules did not cause any conflicts. Repeat the process of going to update.php and choose Date modules updates beginning with 6000 series.

With all CCK and Date fields being converted the Views module could be updated without causing any errors. Repeat the process of going to update.php and choose Views module updates beginning with 6000 series.

At this point, everything for Drupal 6 core and contrib was updated on our site. Now there were some custom things we wanted to do like enable features, disable modules, migrate content types, change date formats, build menus or automate anything we normally did in the UI post upgrade. We had 20 update hooks in a custom module that took care of these processes.

Some things worth noting during our custom update hooks was that update.php ran so early in the bootstrap that not all include files for modules were made available to use. So there were times where we had to use the following functions in our update hooks.

drupal_load('module', 'module_name');


module_load_include('inc', 'module_path/basename');

Repeating the Process

I found that I was repeating many of these steps of going to update.php, disabling updates for some modules, enabling for others. Repeat. So instead of doing this manually, I created browser macros using iMacros for Firefox that helped automate this process. By doing this we were quickly able to run the upgrade path multiple times throughout the development cycle, making tweaks where needed. Since these macros are exportable, each member of our team could run this update locally with consistent results and continually confirm that our upgrade path was still functional.


This is a process that worked for our site. The process worked well for us because we stick with a number of popular contrib modules that had a solid upgrade path of their own. I have shared this process to a few fellow developers that were having troubles upgrading from Drupal 5 to Drupal 6, and surprisingly the process worked just as well for them as it did for us. However, this is no guarantee that this is the Golden Ticket, but it should help get you to a point with fewer error messages. With proper debugging and a bit of custom update hooks, you should be able to finish your migration.

David Burns

That special place where people, code, and business requirements meet is the place that I want to be.

Featured Work

Latest Podcasts

Let's Connect

Want to learn more about working with us or just say hello?

Contact Us