atlassian-cli is an independent, community open-source project, not affiliated with, endorsed by, or sponsored by Atlassian, and is not Atlassian's official CLI (acli). Product names are used only to identify compatibility.

The Two Steps

To convert a markdown to Confluence page, you do two distinct things: convert the markdown into Confluence storage format (Confluence's XHTML-based markup), then publish that markup as a page. Confluence does not store raw markdown, so there is no single "import markdown" button that keeps working at scale. Instead you convert once with a tool like pandoc, then hand the result to the API.

atlassian-cli owns the second step. Its confluence page create and confluence page update commands accept a --body that points at your converted HTML file, so publishing a page becomes one scriptable line. Chain the converter and the CLI together and a markdown file in your Git repo becomes a live Confluence page you can regenerate any time the source changes.

How this differs from Atlassian's own CLI: atlassian-cli is an independent, community open-source project. It is not Atlassian's official CLI (acli) and is not affiliated with, endorsed by, or sponsored by Atlassian. Use the official acli for first-party vendor support; use atlassian-cli if you want a single free Rust binary spanning Jira, Confluence, Bitbucket, and Jira Service Management with the same flags everywhere.

What Confluence Storage Format Is

Before converting anything, it helps to know what you are converting to. Confluence storage format is an XHTML-based markup that Confluence uses to persist page content on disk and over the REST API. Most of it looks like ordinary HTML: paragraphs are <p>, headings are <h1> through <h6>, lists are <ul> and <ol>, and tables are <table>. Those tags map almost directly from what a markdown converter emits, which is exactly why the pipeline works.

The parts that are not plain HTML are Confluence's own features: code blocks with syntax highlighting, info and warning panels, page includes, tables of contents, and status lozenges. Those are represented as macros using the ac: and ri: namespaces. A code block, for example, is not a bare <pre> tag. It is a structured macro:

<!-- Confluence storage format: a code macro -->
<ac:structured-macro ac:name="code">
  <ac:parameter ac:name="language">bash</ac:parameter>
  <ac:plain-text-body><![CDATA[cargo build --release]]></ac:plain-text-body>
</ac:structured-macro>

You rarely write this by hand. The point is that "converting markdown to a Confluence page" means producing this storage-format XHTML, and the closer your converter gets to it, the less cleanup you do later.

Convert Markdown to Storage Format

The most reliable open-source markdown converter is pandoc. Pointed at html output, it produces markup that Confluence's storage format accepts directly: headings, paragraphs, fenced code, links, images, and most tables come across cleanly.

# Convert a single markdown file to Confluence-ready HTML
pandoc -f markdown -t html release-notes.md > release-notes.html

That is the whole conversion step. For a first pass, this output is good enough to publish. Two optional refinements make it read better inside Confluence: a small tweak to give <h1> some top margin, and a class on inline <code> so it picks up Confluence styling.

# Convert with light cleanup for Confluence storage format
pandoc -f markdown -t html release-notes.md \
  | sed 's/<h1>/<h1 style="margin-top: 20px;">/g' \
  | sed 's/<code>/<code class="code-inline">/g' \
  > release-notes.html

Everything downstream treats release-notes.html as the page body. If you would rather build the whole scan-convert-publish loop over a docs directory in one go, the Confluence markdown sync runbook wraps this exact conversion in a ready-to-run script with dry-run support and auto-labeling.

Publish the Page from the CLI

With the storage-format HTML in hand, publishing is a single command. The --body flag accepts a file path, so you pass the converted file straight through:

# Create a new Confluence page from the converted markdown
atlassian-cli confluence page create \
  --space DOCS \
  --title "Release Notes 1.0" \
  --body release-notes.html

For a quick one-off note you can skip the file entirely and pass inline storage format to --body:

# Inline body for a short page
atlassian-cli confluence page create \
  --space DOCS \
  --title "Deploy Log" \
  --body "<p>Shipped the <strong>1.0</strong> release.</p>"

To nest the new page under an existing parent, add --parent with the parent page id. To place it in the right context first, list the space's pages so you can grab an id:

atlassian-cli confluence page list --space DOCS --limit 25
atlassian-cli confluence page create \
  --space DOCS \
  --title "Architecture Overview" \
  --parent 3302031761 \
  --body architecture.html

Update in Place Without Duplicates

Running page create twice makes two pages. For docs that regenerate on every commit, you want an upsert: create the page the first time, overwrite its body on every run after that. The trick is to look up the page id by title, then update by id.

# Find the page id by title with a CQL search
PAGE_ID=$(atlassian-cli confluence search cql \
  "space = DOCS AND title = \"Release Notes 1.0\"" \
  --format json | jq -r '.results[0].content.id // empty')

# Update in place if it exists, otherwise create it
if [ -n "$PAGE_ID" ]; then
  atlassian-cli confluence page update "$PAGE_ID" \
    --title "Release Notes 1.0" \
    --body release-notes.html
else
  atlassian-cli confluence page create \
    --space DOCS \
    --title "Release Notes 1.0" \
    --body release-notes.html
fi

Updating by id overwrites the body and bumps the page version rather than spawning a duplicate. Because pandoc produces the same storage-format output for unchanged input, re-running with an identical source file is effectively a no-op: same title, same body, one clean version bump. That idempotency is what lets you wire the pipeline into CI and forget about it.

You can also tag synced pages so they are easy to find and audit later:

atlassian-cli confluence page add-label "$PAGE_ID" auto-synced

Code Blocks, Tables, and Macros

Most markdown converts cleanly, but three constructs deserve a look before you publish widely. Here is how the common cases behave when you convert markdown to a Confluence page.

Markdown Storage format result Watch for
Fenced code block <pre> or code macro Syntax highlighting needs the code macro; plain <pre> renders without a language.
Pipe table <table> Simple tables convert cleanly; complex GitHub-flavored tables can need manual review.
Inline HTML Passed through Raw HTML that is not valid XHTML may be rejected by the storage-format parser.
Images <img> / attachment ref Relative image paths need to be uploaded as attachments separately.

The practical rule: keep markdown reasonably standard and it converts without fuss. If a page relies on Confluence-native rendering like syntax-highlighted code, expect to post-process pandoc's <pre> output into a code macro, or accept plain preformatted blocks. Always preview a representative page before running the pipeline across a whole space. Local images referenced by relative path are worth handling explicitly: upload them with confluence attachment upload so the published page is not left with broken links.

Round-Trip Back to Markdown

Conversion works in both directions, which matters when someone edits a page in the Confluence web editor and you want that change back in Git. Every command accepts a --format flag, and markdown is a supported output, so a single command pulls a page back out as markdown:

# Export a Confluence page back to a markdown file
atlassian-cli confluence page get 12345 --format markdown > release-notes.md

That closes the loop: publish markdown to Confluence for readers, export it back to keep version control authoritative. For a deeper walkthrough of the reverse direction, including whole-space exports and cleaning up the output, see Export Confluence to Markdown. And if you want to run this as an automated docs pipeline on every merge rather than by hand, the docs-as-code with Confluence guide covers wiring it into CI.

FAQ

How do I convert a markdown file to a Confluence page?

It is two steps: convert the markdown into Confluence storage format, then publish that markup as a page. Run pandoc -f markdown -t html notes.md > notes.html to produce Confluence-compatible XHTML, then run atlassian-cli confluence page create --space DOCS --title "Notes" --body notes.html. The --body flag accepts a file path, so the converted HTML becomes the page content.

What is Confluence storage format?

Confluence storage format is the XHTML-based markup Confluence uses to persist page content. Standard HTML tags like p, h1, ul, and table map across almost directly, while Confluence-specific features such as code blocks, info panels, and page includes are represented as ac:structured-macro elements. When you convert markdown to a Confluence page, you are really converting markdown into this storage format.

Does Confluence support markdown natively?

Not as a storage format. The Confluence editor lets you paste markdown into a page as a one-time convenience, and it converts the text on paste, but the page is still saved as storage format afterward. There is no way to keep a page as raw markdown, which is why a scripted convert-then-publish pipeline is the reliable path for keeping repo docs in sync.

Can I update an existing Confluence page from markdown without creating a duplicate?

Yes. Look up the page id by title with a CQL search, then run atlassian-cli confluence page update PAGE_ID --title "Notes" --body notes.html. Updating by id overwrites the body in place and bumps the version instead of creating a second page, so re-publishing the same file is an idempotent upsert.

How do I get a Confluence page back as markdown?

Every command accepts a --format flag and markdown is a supported output, so atlassian-cli confluence page get 12345 --format markdown returns the page as markdown. That lets you round-trip content back into a Git repository after it was edited in Confluence.

Ready to publish your docs from the terminal? Install atlassian-cli and convert your first markdown file to a Confluence page in minutes.

Related Resources