Move Open edX courses to a self-hosted instance

Moving courses from a hosted Open edX provider to your own instance is mostly a Studio export and import job, but learner data, identity and links need separate planning. This page sets out what maps, what does not travel and how to cut over safely.

On this page

How hard is it to move Open edX courses to a self-hosted instance?

Course content moves from a hosted Open edX provider to your own instance through Studio export and import, with each course packaged as an archive, typically a compressed .tar.gz file. Learner data, enrollments, grades and certificates do not travel with that archive, so they need a separate plan covering who owns that data, how it is extracted from the provider, and what learners see on the first day of the new instance. Treat the course move and the learner data move as two workstreams with different owners and different risks. The effort depends on four things: the number of courses, the volume of assets such as videos, images, documents and static files, the custom XBlocks and frontend components the courses rely on, and the integrations the courses depend on, such as identity, grading or analytics. Ask the provider which courses use custom components and which external tools are embedded, because a course that depends on a component you do not host cannot run until that component exists on your side. Also confirm the Open edX release your provider runs, since your target release will differ and each course needs to be checked against it.

Internal links deserve particular attention. Course components often reference other units, sequences or assets by internal link syntax, and those references can break when a course is imported into a different instance or course identifier. Build a short list of the link patterns your courses use and test each one after import rather than assuming the archive preserved them. Images and files referenced by those components also need to be present in the target course, so compare the asset list in each archive against the pages that display them. Plan for re-runs from the start. A course can be imported more than once, which makes it possible to run a trial import, find problems, fix them in the source or the target, and import again until the course renders and behaves as expected. Agree on a number of trial passes and on the criteria that count as a pass, such as all units rendering, all internal links resolving, and all graded components reporting correctly. Keep a record of each pass so the team can see what changed between runs.

A written scope is the basis for a quote. Ask for an inventory that lists every course, its asset count and size, its custom components, its integrations, its graded elements and the learners who will need access during the cutover. Name the people who sign off on each course, the cutover window and the rollback plan if a course fails verification. DeployOpen works on fixed-scope engagements, so scope, deliverables and timelines are agreed in writing before work starts, and a quote follows from that document. Without the inventory, any quote will carry assumptions that surface later as change requests, so the inventory is the most useful piece of preparation your team can complete before speaking with a partner.

Which course elements map cleanly into a self-hosted Open edX

This table maps each element of a hosted Open edX course to its counterpart in a self-hosted instance and shows whether the Studio export and import path carries it. Rows marked as carried still need a check after import, and rows marked for confirmation need a decision from your provider before cutover. Confirm component behavior against the Open edX release your target instance runs, because component support changes between named releases.

Course elementStudio export and import pathMigration notes
Course structureCarried in the course export package as the section, subsection and unit outlineCheck section and subsection order after import
Units and sequencesCarried as course blocks within the export packageConfirm units appear in the intended order and keep their visibility settings
Text and problem componentsCarried when they use built-in component typesConfirm each problem type is supported in your release and test scored items
Video referencesVideo component settings are carried; hosted video files may not beConfirm whether video files are in the package or hosted by the provider, then rebuild any missing sources
Static assetsFiles in the course assets area are included in the export packageConfirm the package contains every file and that asset paths resolve after import
Grading settingsCarried as course grading policyRecheck weights, grade ranges and assignment types before learners see scores
Course settings and datesCarried as course settings, including start, end and enrollment datesReset dates for your learner calendar and time zone after import
Custom or third-party XBlocksNot carried as code; the export only references the block typesInstall the same plugins in the target instance and confirm versions with the provider
Internal linksCourse-internal location links are expected to resolve if identifiers are keptTest links after import and rebuild any that point to the source platform's domain
Learner recordsNot part of course content and not carried by the course exportEnrollments, grades, submissions and forum data need a separate request to the provider

Which documented export and import paths handle course content

Moving a course from a hosted Open edX provider to your own instance relies on a small set of documented paths. Studio export and import move course content in a .tar.gz package, while the Open edX and Tutor documentation and the edx-platform code explain how to run and verify those steps. Converters for other source formats are covered on sibling pages.

Studio course export package

Studio exports a course as a .tar.gz package that bundles course structure, units, components and assets so the content can move to another instance. Use the export to capture the authored course from the hosted site. Before relying on it, confirm the export steps and the package layout in the documentation for the release your provider runs, because menus and archive contents can change between releases. Record the package name, size and a checksum so the copy can be verified later.

Studio course import and checks

The matching Studio import loads a .tar.gz package into a course on the target instance. Treat the import as the start of verification, not a finished task. Compare the course outline, unit count, video and document assets, and any graded or timed content against the source course. Check the import logs for errors, and confirm that a second import into a new course run behaves the way your re-run plan expects.

Internal link references

Course content often points to other units, components and files through internal link syntax. A link that resolves on the source course can point to a missing identifier on the target, so check these references after import. Sample links in text, sequences and component settings, and confirm the link format for your release in the Open edX documentation before writing any cleanup script. Keep a list of links that failed so the fix is repeatable.

Open edX import and export documentation

The Open edX documentation describes the course import and export process and the archive format for each named release. Use it as the reference for which steps, options and file layout apply to your target. Ask your hosted provider which release and configuration they run, and note any differences between the source and target releases before you plan the move. Verawood is the current named release, so confirm its steps if it is your target.

Tutor for the self-hosted target

Tutor is the official Docker-based Open edX distribution for production and local development, and the edx-platform maintainers recommend running Open edX in production through a service provider or with Tutor. Confirm that the Tutor version and plugins match the Open edX release you import into. Rehearse the import on a non-production instance first, using the Tutor documentation for the commands that deploy and operate the platform.

edx-platform as the code reference

The edx-platform repository contains the Studio and LMS code that performs course export and import. It is licensed under the GNU Affero General Public License version 3 and built on Python, Django and JavaScript. When documentation leaves a question open, have your engineers read the code for the branch or tag that matches your release and check any custom XBlock behavior against it. Learner data is outside the course package and needs its own plan.

What does not travel with course content, such as learner data

A course package carries course content and course settings. Learner records are outside it. When you export from Studio and import into your own instance, the course structure, units, problems and settings move, but enrollments, progress, grades, certificates, discussion posts, user accounts, passwords, instructor-level roles and analytics history do not. Each of these needs its own export, migration or rebuild plan, with a named owner and a named source. Treat the list as a checklist for the cutover, not as a footnote to the import. Reviewing it early tells you which items your team must build, which the provider must deliver, and which you will accept losing.

Ask the provider to confirm in writing what it will supply for each learner-side item: enrollments, grade and progress records, issued certificates, discussion posts, and a list of accounts with their roles. Request the format, the field definitions and the date the extract was taken. Do not assume passwords can be exported. Confirm this explicitly and, if the answer is no, plan for learners to set new credentials through your identity provider. For certificates, confirm whether the provider can supply existing certificate records or whether they must be regenerated and how learners will be told. For discussion posts, confirm the storage backend and the export format before you schedule the cutover.

Your new identity provider determines how each learner is recognized. Open edX third-party authentication supports OAuth2 providers, SAML 2.0, Shibboleth and LTI, along with older provisional options. If the source instance signed learners in through one method and your instance uses another, the same person can appear as a new account with no course history attached. Agree on a matching key with the provider, such as email address, institutional identifier or username, and test it with a small set of accounts on a staging instance. Decide in advance whether duplicate accounts will be merged or kept separate. Instructor-level roles tie to accounts, so your team should expect to reassign them in Studio and the LMS admin tools after import and verify each one.

Analytics history stays with the source unless someone exports it separately. If the provider uses Open edX Aspects, tracking logs are captured as xAPI statements through the event-routing-backends plugin, stored in a ClickHouse database through Ralph or Vector, and presented in Superset dashboards. A course import does not carry that statement store or those dashboards. Ask the provider whether it can deliver raw tracking logs or stored statements, in what format, and for what date range, and confirm whether that data can be loaded into your own ClickHouse store. Until then, reports on the new instance start with an empty history, so tell stakeholders which comparisons across terms will not be possible on day one.

How the move runs from inventory to decommissioning the old course site

The sequence moves each course through inventory, a written provider agreement, a pilot import, a side-by-side check and a controlled cutover before the provider course is retired. No course goes live on the new instance until its content, internal links and learner access have been verified and signed off.

  1. Inventory courses and their dependencies

    The client's course owners list every course on the provider site, with its current run, instructors and enrollment status. Each course is then checked for dependencies that a Studio export does not carry with it, such as uploaded files, externally hosted video, LTI tools, grading integrations, certificates and links to other courses. The client's platform owner signs off the inventory. The step is complete when every course is marked export-ready, needs cleanup or is out of scope, and each external dependency has a named owner.

  2. Agree export access and the learner data request

    The client confirms in writing with the provider that course owners can export each course as a Studio package, which formats are supported, whether any size limits apply and how long exports remain available. Course content travels in the package, but learner data such as enrollments, grades and progress does not. The client's data protection owner decides what learner data to request, in what format and on what legal basis, and the provider confirms what it will supply. Sign-off comes from the data protection owner and the provider's contract contact. The step is complete when the agreement records the export method, the learner data request is logged and the retention window for the provider course is set.

  3. Run a pilot import of one representative course

    The team chooses one course that includes video, several problem types, internal links and file uploads, then exports it as a .tar.gz package from Studio and imports it into Studio on the new instance. Engineers check the section and unit structure, the internal link syntax that points to content inside the course, static asset paths and course settings such as start dates and grading policy. Problems are fixed in the source package or in the imported course, and each attempt is recorded as a course re-run so the team knows which version is live. The course owner accepts the pilot. The step is complete when the course previews with no broken links and the course owner signs the pilot checklist.

  4. Compare old and new courses side by side

    The reviewer opens the provider course and the imported course in separate windows and works through the course unit by unit. The comparison covers text, media, problem answers and feedback, discussion and link targets, certificate wording and any learner-facing dates. Automated link checks catch many issues, but the reviewer also follows each internal link to confirm it lands on the intended content. Differences are either fixed or accepted by the course owner and recorded. The course owner and a DeployOpen reviewer sign the comparison list. The step is complete when every course has a signed comparison with no open differences.

  5. Cut over learner access and update links

    The team opens the new courses to enrollment, moves the learner-facing course addresses and updates DNS records, redirects and links that point to the provider, including those on the marketing site, catalog pages, email templates and partner materials. The provider course is closed to new enrollments where the provider allows it, so learners do not split across two copies. A test learner account enrolls, reaches the content and completes one graded problem end to end. The client's platform owner approves the cutover window, and the course owner confirms learner access. The step is complete when the test path works and every redirect resolves to the new course.

  6. Decommission the provider course after retention

    When the retention window agreed in the provider agreement ends, the client asks the provider to close and remove the old courses and to confirm in writing how learner data has been deleted or returned. The client keeps an archive of the exported packages, the inventory, the signed checklists and the record of the learner data request, stored under its records policy. The client's data protection owner signs off the deletion confirmation. The step is complete when the provider confirms removal in writing and the archive is stored and indexed for future audits.

What drives the cost and duration of a course move

This table lists the effort drivers that change how much work a course move takes and how long it runs, with the question to ask for in each quote. DeployOpen quotes from a written scope and does not publish prices, so these drivers help you define that scope. Inventory, pilot and cutover are one-time work, while support and upgrades after the move recur, and a quote should price them separately.

DriverWhy it mattersWhat to ask for in a quote
Number of courses and sizeEach course needs inventory, export, import and validation, so effort grows with the course count and the number of components in each course.Course count by size band, component totals per course, and which pilot courses are in scope.
Asset and video volumeStatic assets and hosted video must be exported and re-linked, and large libraries add transfer time and storage checks.Total asset size, video sources, and whether videos are re-hosted or re-linked to your video platform.
Custom or third-party XBlocksA course that uses a component missing from your instance will not render correctly until that code is installed and tested.A list of every custom or third-party XBlock in use, with versions and owners to confirm.
Internal link densityInternal links point to course-specific paths, so courses with many links need rewriting and checking after import.Internal link count per course and the method for checking links after import.
Re-runs and course versions in scopeEach re-run or version is a separate package to move, so the choice of which copies to keep sets the volume of work.Which runs and versions to move, which to archive, and whether duplicates are kept.
Learner data scopeEnrollments, grades, progress and discussions do not travel with course content, so moving learner data is a separate piece of work.Whether learner data is in scope, which data fields apply, and the approvals needed to transfer it.
Identity integrationLearners and staff must sign in to the new instance, so identity provider setup and account matching affect cutover timing.Identity providers in use, account matching rules, and who configures and tests the connection.
Branding, theme and languagesTheme changes and each added language require template, content and testing work across every course view learners see.Number of themes and languages, and whether translations come from your team or from the provider.
Parallel run lengthRunning the hosted and new platforms side by side adds support and synchronization work for as long as the run lasts.Length of the parallel run, who supports each platform during it, and the criteria for cutover.

What usually goes wrong in course moves and how to prevent it

These risks appear at different stages: during package export, during import into Studio, after learners sign in, and at cutover. Each card names one risk and a check to run against your own instance before learners arrive. Confirm every check on the target instance rather than assuming the source course or the documentation behaves the same way.

Broken links and missing assets

Internal links point to specific locations inside a course, and asset references point to files carried in the course package. After import, a link can resolve to the wrong target or fail, and an image, video or download can be missing or renamed. Open a link inside every unit, open each image, video and downloadable file as a learner, and search the imported course for the source domain and the old course identifier.

Learner data that never travels

A course export carries course content, while enrollments, grades, submissions, certificates and progress records stay with the source platform unless they are requested through a separate process. Before cutover, list the learner data your organization needs, ask the source provider in writing what they will deliver and in which format, and confirm who owns that data during the transfer. Then verify that a test learner's progress appears on your instance.

Identity mismatches that lock users out

Learners sign in through an identity provider, and the account on your instance must match the identity that provider sends. If identifiers, email addresses or username rules differ between the source and your deployment, users can land in an empty account or fail at sign-in. Configure the identity integration on the target instance before import, create test accounts for each sign-in path, and confirm that the attribute mapping returns the same user on every attempt.

Re-runs under the wrong course identifier

Each course run has an identifier built from the organization, course number and run. If a re-run is imported under an identifier that already exists, or under the wrong one, its content can land in a live run or overwrite one that learners are using. Before import, decide the target identifier for each run, confirm that no course with that identifier exists on the target instance, and check the course URL, enrollment dates and instructor roles after the import finishes.

Custom components that fail on the target release

Custom XBlocks, theme changes and plugins written for one release can break on another, and the target instance runs the release you deploy. An imported course that uses a custom component can show errors or blank units if that component is missing or incompatible. Inventory every custom component the course uses, install the matching versions on the target instance, open each affected unit as a learner, and review the release notes for the release you deploy.

Cutover without a rollback path

A move stays reversible only while the source course remains intact until the target is accepted. Teams that switch learners to the new instance without a documented fallback have no fast way back if content, identity or grades fail after launch. Before cutover, write the steps to return learners to the source, keep source backups until acceptance is signed off, and rehearse the switch on a staging copy that runs the same release and data.

Questions buyers ask before moving Open edX courses

What does it cost to move Open edX courses to a self-hosted instance?

Most of the cost is people's time, plus the infrastructure you run the new instance on. Each course needs an export from the source, a review of its structure and media, a rewrite of internal links where needed, an import, and a test pass that a named owner signs off. Costs that recur include hosting, storage, upgrades and support. If a partner is used, the fee follows the written scope, which lists the courses, their size and the checks included. The main drivers are the number of courses, how many internal links and assets each one holds, how much custom content or assessment work needs rework, and how many sign-off rounds apply. Ask for a quote that shows effort by course group, lists exclusions such as learner data, identity setup and hosting, and states who pays for retesting after import.

How long does moving Open edX courses usually take?

The duration depends on the number and size of courses, the link cleanup they need, how quickly the target environment is ready, and how fast sign-off owners respond. A small set of simple courses moves faster than a large catalog with many assets and assessments, so no single timeline applies to every course set. Ask for a schedule split into phases: environment readiness, a pilot course, the main batch, learner data handling and final sign-off. Confirm which dates depend on your own approvals and access, because those often set the critical path. A fixed-scope agreement records the timeline in writing before work starts, so compare quotes on the phases and assumptions they state, not only on a total.

Do learner progress and certificates move with the course?

No. A Studio course export carries course structure and content, not the learner records around it. Enrollments, progress, grades and certificates issued on the source platform stay there unless you request them separately. Start a learner data request early, listing the records you need, the format the provider can export, and the legal basis your privacy team has confirmed. Then decide whether to migrate history, start fresh on the new instance, or keep the old platform available read-only for a period. Certificate templates and course settings may need checking after import, so confirm the details with your provider and test an issued certificate before learners see it.

What must our team provide before a course move starts?

Start with four things. First, course access: export rights on the source courses or the export packages themselves. Second, a learner data request, covering which records you need and who approves them. Third, identity details for the new instance, including the identity provider, login domains and how learner accounts will match existing ones. Fourth, named sign-off owners for each course, with authority to accept content and approve launch. You also need a target environment with administrator access and a set of test accounts. Missing items usually show up as idle time on the schedule, so list each one in the written scope with a due date and a responsible person.

Can our own team move Open edX courses without a partner?

Often yes for a small set of courses, if your team can operate Open edX, work with Studio export packages and test each course end to end. The edx-platform maintainers recommend running Open edX in production through a service provider or with Tutor, and they note that bare-metal installation is complex and receives limited community support. The platform foundation therefore matters before course work begins. Your team needs skills in Tutor operations, Studio authoring, data handling and quality assurance, plus time for link checks and sign-off. Weigh those skills against your deadlines and course count. A partner can take on the work under a fixed scope, while an internal team can run the process if the owners and time are committed in advance.

What happens to internal links and course re-runs after an import?

Internal links that point to course locations or course keys can break or point to the wrong run after import, so each course needs a link check after the move. Confirm with your release documentation how internal links are written, which identifiers they depend on, and what the import changes. A re-run creates a new course run with its own key and its own enrollments. Learners enrolled in the old run do not move automatically, and links to the old run keep pointing there. Decide, course by course, whether to keep the existing key, create a new run or set up redirects, and record each decision so reviewers can check links against it.

Do learners need accounts on the new instance before the course opens?

Yes. Learners must sign in to the new instance before they can reach the course, and a course export does not create those accounts. Decide how learners will authenticate: local accounts, an existing identity provider, or federated sign-in through an approved protocol. Open edX supports several third-party authentication options, including OAuth2 providers, SAML 2.0, Shibboleth and LTI, with older provisional support for CAS and SSL client certificates. Confirm which option fits your organization, then test how existing learner identities match before cutover. Email addresses or usernames that differ between systems often create duplicate accounts, so check that field first.

How DeployOpen scopes, delivers and supports a course move

DeployOpen scopes a course move from the export your hosted provider or course team produces, then builds the import, link and re-run path on an Open edX instance you control. Each engagement is fixed-scope, with the course inventory, deliverables and timeline agreed in writing before work starts.

How we scope

  • The written scope lists each course, its export package and the target Open edX release for the new instance.
  • Learner data such as enrollments and grades is listed as outside the course move and handled separately.
  • A quote follows from the written scope, and post-handover support is available as a retainer.

How we build

  • Export each course from the source as a Studio .tar.gz package and check the archive contents before import.
  • Test internal link syntax, file references and course identifiers on the target instance before learners see them.
  • Run each import as a repeatable step so re-runs on a corrected package produce the same course structure.

How we hand over

  • Provide an import runbook covering export steps, import commands, link checks and the re-run procedure.
  • Document what did not travel with the course so course teams know what to rebuild or migrate separately.
  • Walk course authors through Studio on the new instance so they can check content and make later edits themselves.

How we support

  • Keep a post-import checklist for course review, link validation and learner access before the course opens.
  • Plan Open edX upgrades against the named release in use, since only the latest named release is supported.
  • Ask whether ongoing support, upgrades and continuous testing should run under a retainer after handover.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.