How to Migrate Your GitHub or GitLab Docs to Confluence (Step-by-Step)

How to Migrate Your GitHub or GitLab Docs to Confluence
Engineering teams often end up with documentation scattered across two places: a docs/ folder in the repo, and a Confluence space that slowly falls behind. This guide shows you how to close that gap — whether you want a one-time migration, a bulk import, or a fully automated sync that keeps Confluence updated on every push.
Why Teams Move Docs to Confluence
Keeping docs in Git is great for developers, but it creates friction for everyone else. Product managers, support teams, and stakeholders usually live in Confluence — not in GitHub. When your README and architecture docs live in a repo, they become invisible to half the company.
At the same time, manually copy-pasting markdown into Confluence is tedious and breaks formatting. The goal is to do this once, correctly, and then keep it in sync automatically.
What You Need
- Confluence Cloud (any plan)
- Markdown Exporter & Importer for Confluence installed
- Your markdown files from GitHub or GitLab (as a ZIP or local clone)
Option 1 — Import a Single File
Best for: migrating a single README, architecture doc, or changelog.
- Open the target Confluence page where you want the content to live
- Click the ••• (More actions) menu → Markdown Importer & Exporter
- Select Import and choose your
.mdor.mdxfile - Preview the output, then click Import
Your markdown — including headers, tables, code blocks, and images — is converted to native Confluence content.
Option 2 — Bulk Import from a ZIP Archive
Best for: migrating an entire docs/ folder from a repo in one shot.
Step 1 — Clone and zip your docs folder
git clone https://github.com/your-org/your-repo.git
cd your-repo
zip -r docs-export.zip docs/
For GitLab, it's the same process — or use the GitLab UI: Repository → Files → docs/ → Download this directory.
Step 2 — Import the ZIP into Confluence
- In Confluence, navigate to the space or page where you want the docs imported
- Open the ••• menu → Markdown Importer & Exporter
- Select Import and upload your
docs-export.zip - Review the file tree — the importer shows all files and their resolved hierarchy before importing
Step 3 — Confirm hierarchy
The importer converts your folder structure into a Confluence page tree. A structure like:
docs/
getting-started/
installation.md
quick-start.md
api/
overview.md
authentication.md
…becomes parent/child pages in Confluence exactly as you'd expect — no manual reorganisation needed.
Step 4 — Handle images and attachments
If your markdown references local images (e.g. ), include the assets folder in the ZIP. The importer uploads them as Confluence attachments and rewires the image references automatically.
Option 3 — Automate with CI/CD (GitHub Actions / GitLab CI)
Best for: keeping Confluence permanently in sync with your repo. Every push updates the docs without anyone touching Confluence manually.
Prerequisites
You'll need two things from the Markdown Importer app:
- In Confluence, go to Settings → Apps → Markdown Importer for Confluence → API tab
- Click Create New Token, give it a label (e.g.
ci-cd-pipeline), set an expiration, and copy it immediately - On the same page, copy your unique API endpoint URL — it looks like:
https://your-site.atlassian.net/wiki/apps/<app-id>/<env-id>/webtrigger - Store both as secrets in your repo:
- GitHub:
Settings → Secrets→CONFLUENCE_API_ENDPOINT+CONFLUENCE_API_TOKEN - GitLab:
Settings → CI/CD → Variables→ same two variables
- GitHub:
You'll also need your Confluence space ID and parent page ID — both are visible in the app's space and page selectors.
GitHub Actions Workflow
Create .github/workflows/sync-docs.yml:
name: Sync docs to Confluence
on:
push:
branches: [main]
paths:
- "docs/**"
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Import README to Confluence
run: |
CONTENT=$(cat docs/README.md | jq -Rs .)
curl -X POST "${{ secrets.CONFLUENCE_API_ENDPOINT }}" \
-H "Authorization: Bearer ${{ secrets.CONFLUENCE_API_TOKEN }}" \
-H "Content-Type: application/json" \
-d "{\"spaceId\":\"DOCS\",\"parentId\":\"123456789\",\"pageTitle\":\"README\",\"content\":$CONTENT,\"overwrite\":true}"
- name: Import API docs
run: |
CONTENT=$(cat docs/api.md | jq -Rs .)
curl -X POST "${{ secrets.CONFLUENCE_API_ENDPOINT }}" \
-H "Authorization: Bearer ${{ secrets.CONFLUENCE_API_TOKEN }}" \
-H "Content-Type: application/json" \
-d "{\"spaceId\":\"DOCS\",\"parentId\":\"123456789\",\"pageTitle\":\"API Reference\",\"content\":$CONTENT,\"overwrite\":true}"
The API sends one page per request as JSON — add a step per file you want to keep in sync. The workflow only triggers when files under docs/ change.
GitLab CI Pipeline
Add to .gitlab-ci.yml:
stages:
- deploy-docs
deploy-confluence:
stage: deploy-docs
only:
- main
script:
- |
curl -X POST "$CONFLUENCE_API_ENDPOINT" \
-H "Authorization: Bearer $CONFLUENCE_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"spaceId\": \"DOCS\",
\"parentId\": \"123456789\",
\"pageTitle\": \"API Documentation\",
\"content\": $(cat docs/api.md | jq -Rs .),
\"overwrite\": true
}"
Store CONFLUENCE_API_ENDPOINT, CONFLUENCE_API_TOKEN as masked CI/CD variables in GitLab.
Tips for a Clean Migration
Organise before you import. Rename files with a numeric prefix if you care about order (01-overview.md, 02-installation.md). The importer preserves file order when importing via the UI.
Handle frontmatter. If your docs use YAML frontmatter (like many Docusaurus or MkDocs setups), the importer reads title from frontmatter and uses it as the Confluence page title. No need to strip it out.
Check internal links. Links between pages (e.g. [see here](../api/overview.md)) are resolved relative to the page hierarchy during import. Cross-check a few after importing to confirm they resolve correctly.
Run a test import first. Pick a small subfolder, import it into a sandbox space, and confirm the output looks right before running the full migration.
Getting Started
Install Markdown Exporter & Importer for Confluence from the Atlassian Marketplace — it's free to try.
For the CI/CD approach, check out the REST API documentation for the full list of parameters, authentication details, and code examples in Node.js, Python, and Go.
Questions or edge cases? Reach out via our support portal — we're happy to help with migration planning.



