We migrated our organization from Confluence Data Center to Confluence Cloud. After the migration, users often ended up on the wrong instance, either following an old DC link to content that had moved to Cloud, or needing to cross-check a Cloud page against its DC version.
To fix this, we built a Forge app that automatically redirects users in both directions. Sharing it here in case it helps others doing similar migrations. Open to questions in the comments.
Happy to discuss trade-offs in the comments.
Two redirect directions, handled by two different frontend modules but the same backend:
The core of the app is a lookup table mapping DC page IDs to Cloud page IDs, plus a handful of fallback strategies for when a direct mapping isn't available.
The whole thing runs on Atlassian Forge. Nothing is self-hosted; there are no external servers. The relevant Forge pieces we used:
One thing worth calling out: because everything lives inside Forge, there's no infrastructure to manage, no separate auth layer to build, and no secrets to store. This makes it easy to divest the DC infrastructure eventually
┌─────────────────────────────────────────────────────────────────────────┐
│ Confluence Cloud (Forge) │
│ │
│ ┌──────────────────────────┐ ┌──────────────────────────────────┐ │
│ │ Frontend Modules │ │ Backend Resolvers │ │
│ │ │ │ │ │
│ │ • Cloud→DC Module │────▶│ • Mapping Lookups │ │
│ │ • DC→Cloud Module │────▶│ • Tracking Writer │ │
│ │ • Admin Settings UI │────▶│ • Statistics & Export │ │
│ └──────────────────────────┘ │ • Schema Migrations │ │
│ └──────────────┬───────────────────┘ │
│ │ │
│ ┌──────────────▼───────────────────┐ │
│ │ Forge SQL │ │
│ │ │ │
│ │ • page_mappings │ │
│ │ • redirect_tracking │ │
│ │ • migration_log │ │
│ └──────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
Confluence Cloud API Confluence DC instance
(page metadata, CQL search) (destination for Cloud→DC)A few design notes:
The mapping data doesn't generate itself. Before (or during) migration, a separate process exports a CSV of DC → Cloud page ID pairs with all the URL variants and metadata. Then:
INSERT ... ON DUPLICATE KEY UPDATE), so re-runs are idempotent — safe to re-run to patch or update rowsFor the batch import itself, we chunk records (around 1,000 per call), dispatch several chunks concurrently, and cap a single run at around 10,000 records. Those numbers were tuned to stay well inside Forge's per-invocation limits; your mileage will vary depending on payload size and Forge SQL latency in your region.
Forge global settings page, admin-only (enforced by Forge). Five sections:
| Tab | Purpose |
|---|---|
| Dashboard | DB health, total mapping count, breakdown by space |
| Test Lookup | Query the mappings table by DC page ID or (space + title) |
| Add Mapping | Manually insert or update a single row |
| Tracking | Daily redirect volume, success/failure rates, paginated log, CSV export |
| Danger Zone | Bulk delete |
The tracking tab turned out to be more valuable than we expected. It's how admins find the "long tail" of broken inbound links that nobody filed a ticket about.
Happy to answer questions on any of this, especially around Forge SQL, the migration system, or the tracking design.
We have added a small js script in the Banner on DC, which takes the dcPage id from the current page, and redirects the user to the cloud URL. Once the cloud page opens, the Forge app takes over the redirection proces as mentioned above.
@Meghdut Mandal wow, I would love to learn more. We have the only cloud redirection app on the Atlassian Marketplace - Redirection for Confluence and we know that migrations are a use case.