Philip Bauer: Migrations! Migrations! Migrations!

published Oct 25, 2019

Talk by Philip Bauer at the Plone Conference 2019 in Ferrara.

I have some upgrade code that you can use, or for some parts copy and adapt for your use case.


Upgrade steps:

  • Do imports in the function.
  • Do them conditional, so it does not fail if some package does not exist.
  • Do not let a step fail when run a second time.

You may want to disable LDAP temporarily in an upgrade step.

Get the birds eye view, with some code that reports:

  • how many items are there
  • which portal types
  • how big
  • local roles
  • etcetera
  • How many items are there that need to be replaced or removed, like PloneFormGen or Collage.

Divide and conquer:

  • Deal with one problem at a time.
  • Ignore problems that don't block you. You may try to solve something in the old Plone 4.3 site which is already fixed just by completing the migration to Plone 5.

You can register upgrade steps conditionally in zcml if needed, for example with zcml:condition="installed plone-52".

Make big problems small:

  • Write something that removes 98 percent of your content, for testing. Keep the structure in place though: Folders may have portlets or local roles that give problems that you want to know of.
  • Do not migrate blobs. The PDF that lives on the filesystem will not change. Move the blobstorage out of the way, use experimental.gracefulblobmissing during migration, and move blobstorage in again.
  • Copy the Data.fs.index too, if it is a really big site.

Forget the past:

  • remove all revisions
  • maybe manually use collective.revisionmanager for this.
  • pack the database with zero days (bin/zeopack keeps the last day by default).
  • Remove no longer needed portlets.
  • You can use uninstall and upgrade profiles. I like having the upgrade code in Python, but sometimes a profile is much easier.
  • Remove utilities and adapters from add-ons that will be removed.
  • Sometimes you cannot easily remove a package. You can make an alias for it. has code for this, for example to not crash on an old site that still expects the kupu editor package somewhere.

Migrating LinguaPlone:

  • Content editors may have done crazy things, combining folders and content from different languages.
  • We have code to migrate this to in migration.plonehelpers.

Update to Plone 5.2:

  • Use Python 2.7 at first.
  • Include Archetypes if needed for migration.
  • Run the migration to migrate to dexterity.

Archetypes to dexterity:

  • Use the methods from pac_migration from
  • Start with the containers/folders.
  • Do one type at a time.
  • Especially for blob-like items there are options to speed this up, like disabling updating SearcheableText.
  • You can write custom migrators, which might just need a few lines.

Alternative: inplace migrator from ftw.upgrade. Interesting for large folders. Might be a nice PR to get this part into core.

To Python 3:

  • We need to remove some archetypes tools.
  • Then remove the Archetypes eggs from buildout and use Python 3.
  • Run the zodbupdate script.
  • When using RelStorage, you may want to switch to filestorage temporarily.
  • Read the documentation please, especially: - upgrade to Python 3 - upgrade zodb to Python 3

Why do it this way? I don't want every Plone company to have their own migration code stashed away somewhere. Please contribute to the core.

Upgrade to Plone 6? Install plone.restapi, use Volto, done.