Confluence CSV Format
Reference
Scope
As of version 9.96.0 (9.96.2 really, as previous versions are seriously flawed), the Confluence module can import Confluence Cloud CSV backups. This document presents their format. It is targeted at:
- technical people working on Confluence migration tools or tools involving Confluence exports
- technical people running migrations who need to deeply investigate some issues
- people curious about the Confluence export format
Introduction
In 2026, Atlassian has been phasing out Confluence XML backups on Confluence Cloud. CSV backups replace them.
Like a Confluence XML package, a Confluence CSV package is a zip file. It contains, among other things, an attachments folder and a CSV file per database table (with a csv.gz extension - mind you, that doesn't always mean they are actually gzipped, see below). While the Confluence XML backup is a hibernate dump, where what's exported is serialized java objects (more or less), CSV files are more directly what's stored in the RDBMS (so for instance if you have ever looked at a PostgresSQL instance containing Confluence server stuff, these CSV file will look quite familiar). Also contrary to Confluence XML backups, there doesn't seem to be an exportDescriptor.properties file: of course, we know where a CSV export comes from: Atlassian's Confluence Cloud.
Like for Confluence XML exports, there are two types of CSV bakups we know about:
- A space backup package, produced from the settings of a space in Confluence.
- A site backup package, produced from the global administration in Confluence. It contains all the spaces, as well as users and groups, but it doesn't necessarily contain the attachments folder.
At the time of writing, there are a few major differences between the site export and the space export, effectively making them slightly different formats.
- About the CSV tables:
- In space backups, the CSV files are at the root of the ZIP archive, and despite their .csv.gz extension, are not actually gzipped, they are stored plain text! (so, on many operating systems, double clicking on them will fail, because your OS will try to gunzip it and of course it can't work.
- In site backups, they are indeed gzipped, and they are in a data folder.
- About the attachment folder:
- In space backups, the attachments folder is structured like in Confluence XML backups: an attachment is found at attachments/<stable page id>/<stable attachment id>/<version number>
- In site backups, an attachment is found at attachments/<uuid> where uuid is given by the FILESTORE_ID property (provided in contentproperties.csv.gz) of the attachment revision record (defined in content.csv.gz)
- About the whiteboards folder: only found in site exports. We haven't looked into the whiteboards yet.
- About the metadata.json file: only found in site exports. It's the somewhat spiritual replacement of the exportDescriptor.properties file found in XML backups. It provides a list of the .csv.gz files in the archive with their sizes in bytes, and some stuff like the backup id, account id, the cloud instance id, things probably mostly relevant to Atlassian's setup. Notably absent from this file would be a backup date. We don't currently use this file.
Description of the CSV tables
| Basename | Columns | Description | Notes / Handling |
|---|---|---|---|
| AO_950DC3_TC_CUSTOM_EV_TYPES | BELONG_SUB_CALENDAR_ID, CREATED, ICON, ID, TITLE | ? - related to calendars | ignored |
| AO_950DC3_TC_DISABLE_EV_TYPES | EVENT_KEY, ID, SUB_CALENDAR_ID | ? - related to calendars | ignored |
| AO_950DC3_TC_EVENTS | ALL_DAY, CREATED, DESCRIPTION, END, ID, LAST_MODIFIED, LOCATION, ORGANISER, RECURRENCE_ID_TIMESTAMP, RECURRENCE_RULE, REMINDER_SETTING_ID, SEQUENCE, START, SUB_CALENDAR_ID, SUMMARY, URL, UTC_END, UTC_START, VEVENT_UID | Calendar | ignored |
| AO_950DC3_TC_EVENTS_EXCL | ALL_DAY, EVENT_ID, EXCLUSION, ID | ? - related to calendars | ignored |
| AO_950DC3_TC_EVENTS_INVITEES | EVENT_ID, ID, INVITEE_ID | ? - related to calendars | ignored |
| AO_950DC3_TC_JIRA_REMI_EVENTS | ALL_DAY, ASSIGNEE, DESCRIPTION, EVENT_TYPE, ID, ISSUE_ICON_URL, ISSUE_LINK, JQL, KEY_ID, STATUS, SUB_CALENDAR_ID, TICKET_ID, TITLE, USER_ID, UTC_END, UTC_START | ? - related to Jira events | ignored |
| AO_950DC3_TC_REMINDER_SETTINGS | CUSTOM_EVENT_TYPE_ID, ID, LAST_MODIFIER, PERIOD, STORE_KEY, SUB_CALENDAR_ID | ? - related to reminder settings | ignored |
| AO_950DC3_TC_REMINDER_USERS | ID, SUB_CALENDAR_ID, USER_KEY | ? - related to reminders | ignored |
| AO_950DC3_TC_SUBCALS | COLOUR, CREATED, CREATOR, DESCRIPTION, ID, NAME, PARENT_ID, SPACE_KEY, STORE_KEY, SUBSCRIPTION_ID, TIME_ZONE_ID, USING_CUSTOM_EVENT_TYPE_ID, LAST_MODIFIED | ? - Related to calendar subscriptions? | ignored |
| AO_950DC3_TC_SUBCALS_IN_SPACE | ID, SPACE_KEY, SUB_CALENDAR_ID | ? - Related to space calendars? | ignored |
| AO_950DC3_TC_SUBCALS_PRIV_GRP | GROUP_NAME, ID, SUB_CALENDAR_ID, TYPE, GROUP_ID | ? - Related to group calendars? | ignored |
| AO_950DC3_TC_SUBCALS_PRIV_USR | ID, SUB_CALENDAR_ID, TYPE, USER_KEY | ? - Related to user calendars? | ignored |
| AO_950DC3_TC_SUBCALS_PROPS | ID, KEY, SUB_CALENDAR_ID, VALUE | ? - Related to calendar property? | ignored |
| audit_affected_object | id, name, type, auditrecordid | ? | ignored |
| audit_changed_value | id, name, oldvalue, newvalue, hidden_oldvalue, hidden_newvalue, auditrecordid | ? | ignored |
| auditrecord | auditrecordid, summary, description, category, address, sysamdin, superadmin, authorname, authorfullname, authorkey, objectname, objecttype, searchstring, creationdate, eventtype, spaceid | ? | ignored |
| bandana | bandanaid, bandanacontext, bandanakey, bandanavalue | ? | ignored |
| bodycontent | bodycontentid, body, contentid, bodytypeid | Contains the body contents of page revisions | fully imported |
| content | contentid, hibernateversion, contenttype, title, lowertitle, version, creator, creationdate, lastmodifier, lastmoddate, versioncomment, prevver, content_status, pageid, spaceid, child_position, parentid, messageid, pluginkey, pluginver, parentccid, draftpageid, draftspacekey, drafttype, draftpageversion, parentcommentid, username, navigationtype | ||
| content_data_classification_mapping | id, classification_level_id, content_id, content_status, creation_date, last_modified_date, classification_source, classification_version_id | ? | ignored |
| content_label | id, labelid, contentid, pagetemplateid, owner, creationdate, lastmoddate, labelableid, labelabletype | Maps labels to contents or templates fully imported | |
| content_perm | id, cp_type, username, groupname, external_group_id, cps_id, creator, creationdate, lastmodifier, lastmoddate | Content permissions | fully imported |
| content_perm_set | id, cont_perm_type, content_id, creationdate, lastmoddate | Content permission sets | fully imported |
| content_relation | relationid, targetcontentid, sourcecontentid, targettype, sourcetype, relationname, creationdate, lastmoddate, creator, lastmodifier | Documents links between pages and wether a page is a copy of another, and possibly other relations | ignored |
| contentproperties | propertyid, propertyname, stringval, longval, dateval, contentid | Content properties | fully imported |
| default_spacerole_assignments | principalid, principaltype, roleid, creator, creationdate, lastmodifier, lastmodificationdate, role_id, deleted_id | ||
| ? | ignored | ||
| extrnlnks | linkid, contenttype, viewcount, url, lowerurl, contentid, creator, creationdate, lastmodifier, lastmoddate | External links | ignored |
| follow_connections | connectionid, follower, followee | Follower/Followee relationship | ignored |
| label | labelid, name, owner, namespace, creationdate, lastmoddate | Labels | fully imported |
| likes | id, contentid, username, creationdate, sequencenum, liked | Liked contents per user | ignored |
| links | linkid, destpagetitle, lowerdestpagetitle, destspacekey, lowerdestspacekey, contentid, creator, creationdate, lastmodifier, lastmoddate | Links between pages | ignored |
| logininfo | id, curfailed, totalfailed, successdate, prevsuccessdate, faileddate, username | ? | ignored |
| notifications | notificationid, contentid, labelid, spaceid, username, creator, creationdate, lastmodifier, lastmoddate, digest, network, contenttype, includechildren | Notifications | ignored |
| os_propertyentry | entity_name, entity_id, entity_key, key_type, boolean_val, double_val, string_val, text_val, long_val, int_val, date_val | ? | ignored |
| pagetemplates | templateid, hibernateversion, templatename, templatedesc, pluginkey, modulekey, refpluginkey, refmodulekey, editorversion, content, spaceid, prevver, version, creator, creationdate, lastmodifier, lastmoddate, bodytypeid | Templates | fully imported |
| space_alias | id, spaceid, lowerspacealias, active, lastmodifieraaid, creatoraaid, lastmodificationdate, creationdate, spacealias | ? | ignored |
| space_owner | id, spaceid, ownerid, ownertype | Space owners | ignored |
| spacepermissions | permid, spaceid, permtype, permgroupname, externalgroupid, permusername, permalluserssubject, creator, creationdate, lastmodifier, lastmoddate, active | ||
| Space permissions | fully imported | ||
| spacerole_assignments | row_id, principal_id, principal_type, role_id, space_id, creator, creationdate, lastmodifier, lastmodificationdate, deleted_id | ? | ignored |
| spacerole_permissions | row_id, role_id, permission_id, creator, creationdate, lastmodifier, lastmodificationdate, deleted_id | ? | ignored |
| spaceroles | role_id, spacerole_type, name, translation_tag, description, internal_use_only, creator, creationdate, lastmodifier, lastmodificationdate, deleted_id | ? | ignored |
| spaces | spaceid, spacename, spacekey, lowerspacekey, spacedescid, homepage, creator, creationdate, lastmodifier, lastmoddate, spacetype, spacestatus | Spaces | fully imported |
| templateattachmentproperties | propertyid, name, value, attachmentid | ? | ignored |
| templateattachments | attachmentid, hibernateversion, name, version, prevver, templateid, creator, creationdate, lastmodifier, lastmoddate | ? | ignored |
| templateproperties | propertyid, hibernateversion, name, value, version, prevver, templateid, creator, creationdate, lastmodifier, lastmoddate | ? | ignored |
| trackbacklinks | linkid, contenttype, viewcount, url, lowerurl, title, blogname, excerpt, contentid, creator, creationdate, lastmodifier, lastmoddate | ? | ignored |
| user_mapping | user_key, username, lower_username, aaid | Maps userkey to username | fully imported |
| usercontent_relation | relationid, targetcontentid, sourceuser, targettype, relationname, creationdate, lastmoddate, creator, lastmodifier | Links contents to user, defining the kind of relationship between the two. | ignored |
| whiteboardContentIds | contentId, spaceId, contentType, referenceId | Seems to define some contents as "whiteboards" | ignored |
Effectively Working with CSV backups
Unfortunately, we don't have much experience in this yet. Compared to Confluence XML, there's no huge file with everything inside it unordered that can be quite challenging to work with. However, you need to deal with gzipped (or not!) CSV files, and with the body field in the bodycontent table that can base64 encoded zstd compressed stuff.
Here are some tips anyway.
Unzip the relevant files
For instance, get the bodycontent table:
From a space export (note how we drop the annoying and wrong .gz file):
unzip -l csv-export.zip bodycontent.csv.gz > bodycontent.csvFrom a site export, add a call to gunzip:
unzip -l csv-export.zip bodycontent.csv.gz | gunzip > bodycontent-with-body-still-encoded.csvTo get the body column of a site export, ignore the first line (CSV header), then take the second field, base-64 decode and then decompress the resulting zstd content:
tail -n +2 bodycontent-with-body-still-encoded.csv | cut -d, -f2 | base64 -d | zstd -d > bodies.txtDecode a unique body value:
echo "KLUv/SAMYQAAPHA+aGVsbG88L3A+" | base64 -d | zstd -d <p>hello</p>Re-encode a body value:
echo '<p>hello</p>' | zstd | base64 KLUv/QRYaQAAPHA+aGVsbG88L3A+CkTGPNg=Use SQLite to work with the CSV tables
SQLite can import and export CSV files.
Let's run sqlite3 in a folder where we have extracted a CSV backup:
$ sqlite3
SQLite version 3.53.2 2026-06-03 19:12:13
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.We can import one or several CSV files, and they are immediately queriable, together:
sqlite> .import content.csv content
sqlite> .import bodycontent.csv bodycontentFor instance, let's imagine we have filtered contents using some criterion with something like this:
sqlite> delete from content where ...;We only want to keep the body contents of the remaining content records:
sqlite> delete from bodycontent where contentid not in (select contentid from content);Now, let's update bodycontent.csv. We set the output mode of SQLite to csv, and disable a limit that would silently truncate long fields, which can happen with body contents. We want headers, and we want to output to bodycontent.csv. We select everything, which will output in the CSV file. And then, we revert to stdout tabs output.
sqlite> .mode csv --charlimit 0
sqlite> .headers on
sqlite> .output bodycontent.csv
sqlite> select * from bodycontent;
sqlite> .output stdout
sqlite> .mode tabs