Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Redirection form Confluence DC to Cloud post Migration using Atlassian Forge

Meghdut Mandal
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
April 16, 2026

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.


What the app does

Two redirect directions, handled by two different frontend modules but the same backend:

  • Cloud → DC: A user on a Cloud page clicks a button and gets taken to the equivalent DC page (if one exists).
  • DC → Cloud: A user follows an old DC link and the app resolves it to the corresponding Cloud page and redirects them there.

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.


Why Forge

The whole thing runs on Atlassian Forge. Nothing is self-hosted; there are no external servers. The relevant Forge pieces we used:

  • Hosted compute (Node.js functions) for backend resolvers
  • Forge SQL for storing the mappings
  • Forge UI Kit for the admin dashboard and the redirect page
  • External fetch permissions declared in the manifest so the app can open the DC Page without any issues

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

High-level architecture

┌─────────────────────────────────────────────────────────────────────────┐
│                         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 countdown is there partly for UX (users see what's happening and where they're going) and partly so the resolver has time to complete without making navigation feel instantaneous-but-broken when something fails.
  • Every attempt is tracked, including failures. This is what lets the admin team spot pages that have broken links pointing at them and add missing mappings.
  • The three input shapes mean the app can handle links that were copy-pasted out of wikis in various styles over the years.

How the mappings get loaded

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:

  1. A batch script reads the CSV and sends records to a backend resolver via GraphQL
  2. The resolver performs an upsert (INSERT ... ON DUPLICATE KEY UPDATE), so re-runs are idempotent — safe to re-run to patch or update rows
  3. Admins can also add, correct, or delete individual mappings through the dashboard UI

For 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.


Admin dashboard

Forge global settings page, admin-only (enforced by Forge). Five sections:

TabPurpose
DashboardDB health, total mapping count, breakdown by space
Test LookupQuery the mappings table by DC page ID or (space + title)
Add MappingManually insert or update a single row
TrackingDaily redirect volume, success/failure rates, paginated log, CSV export
Danger ZoneBulk 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.


Things that worked well

  • Keeping everything in Forge. Zero infrastructure.
  • Tracking every DC → Cloud attempt. Track every redirect attempt.
  • Idempotent batch import. Being able to re-run the import without fear made mapping corrections painless.
  • Fallback chain for URL resolution. Direct page ID → display URL → error. Users almost never hit the error tier in practice.

Things I'd think about if starting over

  • Forge SQL limits. Batch import sizing needs careful tuning. Worth prototyping early with realistic data volumes.
  • Cutoff date handling. Ours is a single date. If your migration happens in waves per space, you'd want a per-space cutoff instead.
  • Admin UX for bulk corrections. Our dashboard handles one row at a time, which is fine for occasional fixes but painful if you discover a systematic mapping issue.

Happy to answer questions on any of this, especially around Forge SQL, the migration system, or the tracking design.



2 comments

Comment

Log in or Sign up to comment
Darryl Lee
Community Champion
April 16, 2026

This sounds amazing. I don't suppose you will be planning to open source the code?

Wondering how the DC redirection works. Do you have an additional server to redirect to your Forge app's endpoints on your Cloud instance?

Meghdut Mandal
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
April 17, 2026

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.

Stavros_Rougas_EasyApps
Atlassian Partner
April 17, 2026

@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.

TAGS
AUG Leaders

Atlassian Community Events