Send us a message and we'll get back to you shortly.
The Open edX upgrade path from Lilac or any later release to Verawood with Tutor: the Tutor version and what breaks at each hop, the row-count check and the rollback.
You cannot skip named releases. Cubite runs managed Open edX from $1,260 a month for up to 1,000 concurrent learners, and named-release upgrades are included in every managed tier. This runbook is for teams that upgrade their own Tutor installation: it takes a site from Lilac, or any later release, to Verawood one release at a time, with the Tutor version for each hop, what breaks, the checks to run after each hop and the way back.
Short answer (updated October 26, 2026): each Open edX named release has its own Tutor major version, from Tutor 12 for Lilac to Tutor 22 for Verawood, so going from Lilac to Verawood takes ten hops, one release at a time. For each hop, back up the platform, install the next Tutor major, run the launch command, then check that your counts of users, enrollments and certificates have not dropped. Tutor does not support downgrading, so the backup you take before each hop is your rollback.
As of October 26, 2026, Verawood (released July 30, 2026, on Tutor 22) is the only supported Open edX release. Willow, the next one, is planned for a release cut in early January 2027 and a release in late February 2027, as the Build-Test-Release working group confirmed on October 5, 2026. The Open edX release table lists every release with its Tutor version and support status, and Cubite's free upgrade-path checker lists the hops from your release.
Open edX periodically squashes its Django database migrations, so a database has to pass through each release in turn, and Tutor's upgrade steps, such as the MongoDB version upgrades, are written per release. Tutor's upgrade guide describes moving "from one major version to the next" and warns that "any upgrade is final because downgrading is not supported". When Aulasneo took a client from Lilac to Ulmo, nine releases in one maintenance window, the team built a minimal Docker image for each release from Koa onward just to run the migrations (their write-up on the Open edX forum, September 1, 2026).
tutor local stop, then sudo rsync -avr "$(tutor config printroot)/" /var/backups/tutor-before-maple/. Name the folder after the release you are moving to, and keep a copy off the server.pip install "tutor[full]~=13.0" for Maple, the same range as Tutor's own pins (the table below gives the major for each hop). Upgrade your own plugins to releases built for that major.tutor local launch (tutor local quickstart on Tutor 14 and earlier). Tutor sees that the environment was generated by the older release and runs that release's upgrade steps once.tutor config save, so run them yourself: tutor config save, tutor images build openedx (plus any other image you customize), tutor local upgrade --from=lilac with the release you are leaving, then tutor local launch (quickstart on Tutor 14 and earlier).Each row is one hop. The Tutor column is the major to install for it: pip install "tutor[full]~=N.0" picks that major's latest patch, the same range that Tutor's table of older releases pins. The middle column is a selection of the changes in Tutor's changelog, most of them marked as breaking, plus what Tutor's upgrade step does for that release and, where noted, what changes in the release itself; read the full list against your own plugins and customizations.
| Hop | Tutor | What changes or breaks (Tutor, unless noted) | Check after the hop |
|---|---|---|---|
| Koa to Lilac | v12 | MongoDB goes to 4.0 in Tutor's upgrade step; Python-evaluated problem input is off by default, as Tutor does not run codejail; the Android app and the web UI leave core Tutor for plugins | MongoDB runs 4.0; courses open; problems that run Python still grade |
| Lilac to Maple | v13 | Caddy replaces the Nginx container, so custom nginx patches become caddyfile patches; every container runs unprivileged; the forum moves to the tutor-forum plugin; the legacy courseware is no longer supported, so Tutor's upgrade step enables the mfe plugin and learners move to the Learning MFE | Discussions load with the forum plugin enabled; courseware opens in the Learning MFE; custom web-server rules moved to Caddy |
| Maple to Nutmeg | v14 | lms.env.json and cms.env.json become YAML files, so plugin patches to them must be rewritten as YAML; persistent grades are on by default | Plugins load; course tabs and outlines appear |
| Nutmeg to Olive | v15 | quickstart becomes launch and init becomes do init; plugins that reached edx-platform through the openedx-dockerfile-post-python-requirements patch must move to openedx-dockerfile-pre-assets | Custom images build; grades show on the progress page |
| Olive to Palm | v16 | Docker Compose V2 is required; MySQL goes from 5.7 to 8 and MongoDB to 4.4; the hooks API changes break older custom plugins; the ORA2 upload folder is renamed. The version range installs the latest 16.x, which runs MySQL 8.1 and carries the 16.1.0 fix for data broken during the Olive to Palm migration (a utf8mb3 and utf8mb4 mismatch) | Accented text and emoji read back correctly; ORA2 uploads open |
| Palm to Quince | v17 | Images build with BuildKit only; Python packages added through private.txt are no longer supported (use tutor mounts); the Indigo theme is switched on when no other theme is set | Your own theme is still the active one; extra Python packages installed |
| Quince to Redwood | v18 | MongoDB goes from 4.4 to 7.0 by way of 5.0 and 6.0, which Tutor's upgrade step runs (on Kubernetes it prints the commands instead); MySQL goes to 8.4; openedx-assets gives way to npm run; translations come from atlas, which ends custom openedx-i18n locales; a fork set in EDX_PLATFORM_REPOSITORY must end in .git | MongoDB runs 7.0; theme assets compile; your languages still load |
| Redwood to Sumac | v19 | Meilisearch replaces Elasticsearch; tutor local do convert-mysql-utf8mb4-charset converts existing tables to utf8mb4, which Tutor warns is potentially irreversible and may take a long time (the single longest step in #19509); forum v2 keeps existing forum data in MongoDB until you migrate it to MySQL | Course, courseware and Studio search return results; every table converted to utf8mb4 |
| Sumac to Teak | v20 | Before this hop, move forum data from MongoDB to MySQL with tutor local run lms ./manage.py lms forum_migrate_course_from_mongodb_to_mysql all, which the tutor-forum README calls non-destructive and safe to re-run (openedx/forum 0.4.3 removed the MongoDB backend). The site-configuration script is removed in favor of the create_or_update_site_configuration command. From #19509: the forum migration after Sumac needed FORUM_MONGODB_DATABASE patched back in, and Teak's Meilisearch reindex stalled init on a small instance | Forum threads survived the move to MySQL; the search index is complete |
| Teak to Ulmo | v21 | uv replaces pip in image builds (VCS editable requirements need a MANIFEST.in, or PIP_COMMAND=pip); the WebUI plugin is removed in favor of Tutor Deck; the preview page setting is removed now that the Learning MFE serves it; on Kubernetes, patchesStrategicMerge becomes patches | Custom requirements install; course preview opens |
| Ulmo to Verawood | v22 | Tutor needs Python 3.10 or later; Meilisearch 1.36 cannot read the old index, so it is deleted and rebuilt (below). Beyond Tutor, in Verawood itself: the new Instructor Dashboard replaces the legacy one, and sections injected through InstructorDashboardRenderStarted no longer appear; two migrations can stop on old data, and notifications are on by default (below) | Search works after the reindex; instructor-dashboard customizations still present; notifications set the way you want |
On the Ulmo to Verawood hop, Meilisearch 1.36 restart-loops on the old index ("database version (1.8.4) is incompatible with your current engine version (1.36.0)"), so rebuild the index during that hop, as Tutor's changelog gives it: stop the platform, delete the old index, start it, re-run init, then reindex Studio and the active courses: tutor local stop, rm -rf "$(tutor config printroot)/data/meilisearch/data.ms", tutor local start -d, tutor local do init, tutor local exec cms ./manage.py cms reindex_studio and tutor local exec cms ./manage.py cms reindex_course --active. On a large site the reindex takes a while, and search stays incomplete until it finishes. For Verawood's own changes beyond Tutor, see what is new and what breaks in Verawood.
Verawood's Developer and Operator Release Notes also list two migrations that can stop on old data, and a default that changed:
On a release older than Koa: Tutor's table of older releases starts at Koa (Tutor 11), and its upgrade command carries steps back to Ironwood, so the same one-release-at-a-time rule applies from there. A site that was installed without Tutor has to move onto Tutor first, which is a project of its own.
An upgrade should not remove accounts, enrollments or certificates, so three counts are a quick check that a hop kept your data. Take them before the first hop, on the staging copy and again at the start of the production window, and after every hop: none of the three may drop. Tutor's init can add a service account, so a small rise in users is expected: at the Lilac to Maple hop, Tutor 13's init creates one called cms. The counts come from the auth_user, student_courseenrollment and certificates_generatedcertificate tables, in the database Tutor names in OPENEDX_MYSQL_DATABASE (openedx by default). With Tutor's own MySQL, this command runs the count in the mysql container, in the same pattern as Tutor's database-dump command:
tutor local exec -e USERNAME="$(tutor config printvalue MYSQL_ROOT_USERNAME)" -e PASSWORD="$(tutor config printvalue MYSQL_ROOT_PASSWORD)" -e DB="$(tutor config printvalue OPENEDX_MYSQL_DATABASE)" mysql sh -c 'mysql --user=$USERNAME --password=$PASSWORD $DB -e "SELECT (SELECT COUNT(*) FROM auth_user) AS users, (SELECT COUNT(*) FROM student_courseenrollment) AS enrollments, (SELECT COUNT(*) FROM certificates_generatedcertificate) AS certificates"'
If a number drops, stop: restore the backup from before that hop, and find the cause on staging before you try the hop again.
Tutor does not support downgrading, so a failed hop is rolled back from the backup you took before it: stop the platform and restore the backed-up Tutor root with --delete, so that files the newer release wrote, such as a MySQL 8 data directory or a Meilisearch 1.36 index, do not survive: sudo rsync -a --delete /var/backups/tutor-before-maple/ "$(tutor config printroot)/". Then reinstall the Tutor major you were on and start the platform with tutor local start -d. Restore any MySQL or MongoDB that runs outside Tutor from its own backup at the same time. Coming back from Verawood, the old search index has to come from that backup too: Tutor's changelog notes that Meilisearch 1.8.4 cannot read an index written by 1.36.0. Rehearse the restore on staging before the production window, so you know how long it takes.
A detailed recent account on the Open edX forum is Aulasneo's Lilac to Ulmo upgrade (discuss #19509, September 1, 2026), done in a one-hour window after two months of preparation. What cost them the most time:
| Your situation | Upgrade it yourself | Have it managed |
|---|---|---|
| One release behind, standard plugins, and someone who has run a Tutor upgrade | Good fit | Optional |
| Several releases behind, with custom plugins, a custom theme or a fork | Possible: rehearse every hop on staging | Worth pricing |
| No one on staff who knows Tutor, Docker and Django migrations | Risky | Good fit |
Cubite is one of the managed options and publishes this runbook. Named-release upgrades are included in every managed Open edX tier (Lean $1,260 a month, Resilient $1,850 a month, Scale from $3,400 a month), each rehearsed on a UAT environment before production. See managed Open edX. A platform Cubite takes over starts on the release it already runs, and bringing it up from an unsupported release is a fixed quote agreed before the managed term starts. If you keep the upgrade in-house but need a plugin, theme or XBlock ported to a new release, see Open edX development.
Named-release upgrades are included in every managed Open edX tier, each rehearsed on a UAT environment before production. Running an unsupported release? Bringing it current is a fixed quote, agreed before the managed term starts.