[Offline Transfer] Beta Frontend Implementation
<!--IssueSummary start--> #### Key Resources Experiment epic https://gitlab.com/groups/gitlab-org/-/epics/8985 **Beta epic (after experiment)** https://gitlab.com/groups/gitlab-org/-/work_items/21009 Architecture design https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/offline_direct_transfer_migrations/ #### Feature flags `offline_transfer_exports` `offline_transfer_imports` `offline_transfer_ui` ## Overview Currently, direct transfer requires a network connection between the source and destination GitLab instances throughout the migration process.  As mentioned in the [architectural overview](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/offline_direct_transfer_migrations/#motivation), customers with no network connectivity between their GitLab instances or with strict network policies are unable to use direct transfer. These customers must use file-based import/export to manually export and import each group separately or ask for help from Professional Services. It’s a tedious process and [file-based group transfer is deprecated](https://docs.gitlab.com/user/project/settings/import_export/#migrate-groups-by-uploading-an-export-file-deprecated). ### User profile As noted in the [backend plan](https://gitlab.com/groups/gitlab-org/-/epics/8985), **the proposed Offline Transfer feature will be used by customers who**: * _Don't allow ANY outside access to their network for various reasons (internal policy, gov't policy)_ * _Don't want to allow an IP range required for online DT_ * _Cannot quickly and easily get an IP added to their firewall system_ * _Have strict restrictions on what lives on the external machines that can connect to their networks (must have this specific VPN, antivirus, etc)_ ## Timeline At present, offline transfer will be API-only, in line with the Experiment epic. The frontend will be underway starting from 18.10 but not integrated to backend until V1 of the backend is completed. Offline Transfer via UI will thus be released after the API option is released, as part of the [Beta](https://gitlab.com/groups/gitlab-org/-/work_items/21009) phase. Targetted milestone is 19.4 or 19.5. ### Implementation plan | Task | Start | End | Status | |------|-------|-----|--------| | Scaffold app, routes | 18.10 | 18.11 | :green_check_mark: Done | | UX planning and designs | 18.7 | 19.0 | :green_check_mark: Done. Refinements by Import ongoing | | Form stepper | 18.11 | 19.0 | :green_check_mark: Done | | Complete exporting flow | 19.1 | 19.3 | In progress - Delayed to 19.3 | | Landing page, navigation. | 19.2 | 19.2 | :green_check_mark: Done (refinements underway) | | Complete importing flow and import history (simplified). Export history page. Finalize rollout strategy | 19.4 | 19.4 | | | Admin permission in settings. e2e or integrations testing. Documentation, Beta release. Refinements. | 19.5 | 19.5 | Admin setting done. | ## Design / UI https://gitlab.com/gitlab-org/gitlab/-/issues/581545 https://www.figma.com/design/1uiBnqdUpMXV22OlpL7PAz/--581545--Offline-Transfer?node-id=4018-3618&t=FXyqQwTMIgMi9Sea-0 #### Feature discovery (how does user know it exists) As of Feb 2026, product design is aiming towards * Possibly a nav link for Imports / Exports in the side bar. Though where it should go is TBD * a consolidated landing page for all group-level imports and exports that offers both direct transfer and offline transfer * Clicking on the offline transfer option then takes any logged in user to the tool (or perhaps an Export link and Import link) * We may need some other visual cues in the UI, such as on the group or groups page. ## Stories As a user, I want to safely and securely move my groups and projects between GitLab instances without needing a sustained network connection. #### When logged into the source instance, I want to * safely connect to a storage provider such as AWS * choose the \[top-level\] groups ~~or projects~~ on the source instance that I wish to be exported to the storage facility; * see basic status information on the exports progress Eg. pending, failed, successful; * receive an email notification when the export is complete, that does not expose sensitive information. #### When logged into the destination instance, I want to: * safely connect to the storage provider  * ~~view my exported files or entities~~ (See below) * Map where those entities should go (destination namespace or path) * Start the import * Monitor import progress * receive an email notification when the import is complete that does not expose sensitive information. #### In later versions of the offline transfer feature * I want to choose projects within groups * I want to choose subgroups within groups, not just top-level groups * On the source instance, I want to be able to choose from multiple storage providers, eg. Google Cloud, Azure, etc. * Possibly, be able to turn off notifications for import/export * I want to view my exported files or entities and select which ones to import, instead of importing everything ## Frontend Development Questions ### Permissions and eligibility * Which tiers or platforms can use offline transfer? * It will be available to all tiers and platforms. No need to distinguish between EE and free versions. * This likely means that any signed in user can access the offline transfer feature. They just won't be able to export or import anything they lack the correct permissions for. * Is there a required user role to use? * It should be treated the same way as direct transfer. * The offline/export frontend will show the user only groups that they own to select for export. See https://gitlab.com/gitlab-org/gitlab/-/work_items/586918#note_3386783495 * In direct transfer, a user has to have the `:admin_project` to export projects (at least project maintainer role) and `:admin_group` to export groups (group owner role). Since permission to export is relative to each entity, we don't have a single permission requirement for a direct transfer migration or offline transfer export as a whole. * Is usage gated by an admin setting (similar to DT)? * Yes. But the current suggestion is to have separate toggles for offline transfer exports vs. imports. https://gitlab.com/groups/gitlab-org/-/epics/8985#note_3058751982 * ##### Storage providers * V1: AWS S3 only (hardcoded or single option in a dropdown). Maybe note 'more providers coming' Later versions could include: * Multi-provider support with form abstraction * Future: Admin-level provider restrictions ##### Progress of Import / Export How will frontend monitor export / import progress? Unlike direct transfer, there shouldn't be as intricate of a polling mechanism between both source and destination instance. Instead, the two phases operate independently with simpler status tracking (to be confirmed!) * During the export phase: The source instance tracks upload progress as files are written and uploaded to object storage. The frontend will monitor this progress via real-time updates. * **During import:** The destination instance fetches the metadata file from storage and processes it. Since files are already complete in storage when import begins, there's no need for cross-instance polling. The frontend could then be notified when the metadata is ready for the user to map imports. **History page** Initially, the polling mechanism: ~~WebSocket /~~ GraphQL subscriptions, possibly. , to check for updates on the history/status page For V1, we'd keep it as a simple GET request on page load or refresh. #### **Form Fields** **When exporting** Exporting will involve using an AWS access key ID and and AWS secret access key. These connections are per-import, and backend will delete delete configuration credentials 24 hours after import or export so they don't stay stored longer than necessary and to be consistent with direct transfer. During an export or import, they'll be encrypted and stored in PostgreSQL. **When importing** Users need to provide a bucket and the export prefix generated by the export. Objects are accessed with keys, like a hash without any nesting. **Objects don't have paths**, even though their keys may have `/`s and look like it. Object prefixes are just a substring of a key, but for most intents and purposes it works like a path. We should avoid using "path" or "folder". Use "prefix" or "key" to match object storage terminology ([AWS docs](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-prefixes.html)) ### Testing strategy * E2E tests * Component level tests * Integration tests ### Security / credentials management Credentials are not stored in the browser or session. User enters S3 credentials in the form. They are sent to backend via POST once. Eg. `POST /offline_exports` The backend encrypts and stores in database , and frontend never sees them again not stores them. ### Backend **Key endpoints** 1. GET /offline_exports & /offline_exports/:id -\> https://gitlab.com/gitlab-org/gitlab/-/work_items/538940 2. POST /offline_exports -\> https://gitlab.com/gitlab-org/gitlab/-/work_items/576099 3. GraphQL groups query (for accessing entities the user has permissions for) **Models / Tables** Import::Offline::Exports Import::Offline::Configurations **Notifications** When export completes or fails -\> https://gitlab.com/gitlab-org/gitlab/-/merge_requests/234816 When import completes or fails TBA ## Timeline (as of 18.11) https://gitlab.com/gitlab-org/gitlab/-/work_items/581545#note_3178255806 # Outstanding Questions (as of Feb 2026) **Cross-tier or cross platform transfer**s: Is that a thing? Is there a need to validate cross-instance (tier, platform) compatibility? What happens when importing from a higher tier/platform to a lower tier/platform or vice versa? ## Other concerns #### Metrics * Num or proportion of customers using offline transfer vs direct transfer * success rate of imports/exports * support tickets? Reduction in requests to Professional services ### Performance considerations TBD ### Export statuses TBA ### Import statuses TBA ### Documentation updates TBC <!--template sourced from https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/issue_templates/Default.md-->
epic