export format
Calcillo documents can be exported as self-contained JSON files for backup, sharing, and interoperability.
File Format
- File extension:
.calcillo - Content type:
application/vnd.cloudillo.calcillo+json - Format version:
3.0.0 - Encoding: UTF-8 JSON
v3 generic export format
Since format version 3.0.0, Calcillo uses the generic exportYDoc() serializer from @cloudillo/crdt. All Yjs types carry inline @T type markers and data keys match the raw CRDT shared type names. See v3 Generic Export Format for the full specification.
Envelope Structure
{
"contentType": "application/vnd.cloudillo.calcillo+json",
"appVersion": "0.1.0",
"formatVersion": "3.0.0",
"exportedAt": "2026-02-20T10:00:00.000Z",
"data": {
"meta": { "@T": "M", ... },
"sheetOrder": [ "@T:A", ... ],
"sheets": { "@T": "M", ... }
}
}Envelope Fields
| Field | Type | Description |
|---|---|---|
contentType |
string |
Always "application/vnd.cloudillo.calcillo+json" |
appVersion |
string |
Calcillo version that created this export |
formatVersion |
string |
Export format version (currently "3.0.0") |
exportedAt |
string |
ISO 8601 timestamp of export |
Data Fields
| Key | @T |
Yjs Type | Description |
|---|---|---|---|
meta |
M |
Y.Map |
Document metadata (name, initialized flag) |
sheetOrder |
A |
Y.Array<SheetId> |
Sheet IDs in tab order |
sheets |
M |
Y.Map<YSheetStructure> |
All sheets keyed by SheetId |
Sheet Structure
Each sheet in the sheets map is a Y.Map (@T: "M") containing nested shared types:
| Key | @T |
Yjs Type | Description |
|---|---|---|---|
name |
T |
Y.Text |
Sheet name (with text and delta fields) |
rowOrder |
A |
Y.Array<RowId> |
Row IDs in display order |
colOrder |
A |
Y.Array<ColId> |
Column IDs in display order |
rows |
M |
Y.Map<Y.Map<Cell>> |
Nested: rowId → colId → Cell |
merges |
M |
Y.Map<MergeInfo> |
Merge definitions keyed by composite key |
borders |
M |
Y.Map<BorderInfo> |
Border definitions keyed by composite key |
hyperlinks |
M |
Y.Map<HyperlinkInfo> |
Hyperlink definitions keyed by composite key |
validations |
M |
Y.Map<ValidationRule> |
Validation rules keyed by validation ID |
conditionalFormats |
A |
Y.Array<ConditionalFormat> |
Ordered conditional formatting rules |
hiddenRows |
M |
Y.Map<boolean> |
Hidden row flags |
hiddenCols |
M |
Y.Map<boolean> |
Hidden column flags |
rowHeights |
M |
Y.Map<number> |
Custom row heights in pixels |
colWidths |
M |
Y.Map<number> |
Custom column widths in pixels |
frozen |
M |
Y.Map<string | number> |
Freeze pane settings |
Sheet names are Y.Text in v3
The name field is serialized as a Y.Text with @T: "T", containing both text and delta fields. This preserves any concurrent edit state. In pre-v3 exports, sheet names were plain text strings from Y.Text.toString().
Default cell values are stripped
Calcillo applies a transformSheets post-processing step that removes default cell property values to reduce export size. Empty rows (containing only the @T marker) are also omitted.
Numeric Precision
All numeric values are rounded to 3 decimal places in the export to produce cleaner output. Cell values retain their original precision.
Complete Example
A spreadsheet with 2 sheets. The first sheet has values, a formula, styling, a merge, and a border. The second sheet is a simple data table.
{
"contentType": "application/vnd.cloudillo.calcillo+json",
"appVersion": "0.1.0",
"formatVersion": "3.0.0",
"exportedAt": "2026-02-20T10:00:00.000Z",
"data": {
"meta": {
"@T": "M",
"initialized": true,
"name": "Q1 Sales Report"
},
"sheetOrder": ["@T:A", "aB3x_Qm7kL9p", "Xk2nR8vH_wYq"],
"sheets": {
"@T": "M",
"aB3x_Qm7kL9p": {
"@T": "M",
"name": {
"@T": "T",
"text": "Summary",
"delta": [{ "insert": "Summary" }]
},
"rowOrder": ["@T:A", "r_Hw5qT2m", "r_m4JfL1p", "r_Nz9cKvW", "r_Qp4rW9x"],
"colOrder": ["@T:A", "cAb3x", "cXk2n", "cM4Jf", "cNz9c"],
"rows": {
"@T": "M",
"r_Hw5qT2m": {
"@T": "M",
"cAb3x": {
"@T": "M",
"v": "Product",
"bl": 1,
"bg": "#e3f2fd",
"ht": 2
},
"cXk2n": {
"@T": "M",
"v": "Q1",
"bl": 1,
"bg": "#e3f2fd",
"ht": 2
},
"cM4Jf": {
"@T": "M",
"v": "Q2",
"bl": 1,
"bg": "#e3f2fd",
"ht": 2
},
"cNz9c": {
"@T": "M",
"v": "Total",
"bl": 1,
"bg": "#e3f2fd",
"ht": 2
}
},
"r_m4JfL1p": {
"@T": "M",
"cAb3x": { "@T": "M", "v": "Widget A" },
"cXk2n": {
"@T": "M",
"v": 15000,
"ct": { "@T": "M", "t": "n", "fa": "$#,##0.00" }
},
"cM4Jf": {
"@T": "M",
"v": 18500,
"ct": { "@T": "M", "t": "n", "fa": "$#,##0.00" }
},
"cNz9c": {
"@T": "M",
"v": 33500,
"f": "=B2+C2",
"ct": { "@T": "M", "t": "n", "fa": "$#,##0.00" },
"bl": 1
}
},
"r_Nz9cKvW": {
"@T": "M",
"cAb3x": { "@T": "M", "v": "Widget B" },
"cXk2n": {
"@T": "M",
"v": 22000,
"ct": { "@T": "M", "t": "n", "fa": "$#,##0.00" }
},
"cM4Jf": {
"@T": "M",
"v": 19800,
"ct": { "@T": "M", "t": "n", "fa": "$#,##0.00" }
},
"cNz9c": {
"@T": "M",
"v": 41800,
"f": "=B3+C3",
"ct": { "@T": "M", "t": "n", "fa": "$#,##0.00" },
"bl": 1
}
},
"r_Qp4rW9x": {
"@T": "M",
"cAb3x": {
"@T": "M",
"v": "Grand Total",
"bl": 1,
"it": 1
},
"cNz9c": {
"@T": "M",
"v": 75300,
"f": "=D2+D3",
"ct": { "@T": "M", "t": "n", "fa": "$#,##0.00" },
"bl": 1,
"bg": "#fff9c4"
}
}
},
"merges": {
"@T": "M",
"r_Qp4rW9x_cAb3x": {
"@T": "M",
"startRow": "r_Qp4rW9x",
"endRow": "r_Qp4rW9x",
"startCol": "cAb3x",
"endCol": "cM4Jf"
}
},
"borders": {
"@T": "M",
"r_Hw5qT2m_cAb3x": {
"@T": "M",
"bottom": { "@T": "M", "style": 2, "color": "#1565c0" }
},
"r_Hw5qT2m_cXk2n": {
"@T": "M",
"bottom": { "@T": "M", "style": 2, "color": "#1565c0" }
},
"r_Hw5qT2m_cM4Jf": {
"@T": "M",
"bottom": { "@T": "M", "style": 2, "color": "#1565c0" }
},
"r_Hw5qT2m_cNz9c": {
"@T": "M",
"bottom": { "@T": "M", "style": 2, "color": "#1565c0" }
}
},
"hyperlinks": { "@T": "M" },
"validations": { "@T": "M" },
"conditionalFormats": ["@T:A"],
"hiddenRows": { "@T": "M" },
"hiddenCols": { "@T": "M" },
"rowHeights": { "@T": "M" },
"colWidths": {
"@T": "M",
"cAb3x": 150,
"cXk2n": 120,
"cM4Jf": 120,
"cNz9c": 120
},
"frozen": {
"@T": "M",
"type": "row",
"rowIndex": 1
}
},
"Xk2nR8vH_wYq": {
"@T": "M",
"name": {
"@T": "T",
"text": "Raw Data",
"delta": [{ "insert": "Raw Data" }]
},
"rowOrder": ["@T:A", "r_Jx8mP3q", "r_Vn4wK7r", "r_Bt6yH2s"],
"colOrder": ["@T:A", "cPq7r", "cWm3s"],
"rows": {
"@T": "M",
"r_Jx8mP3q": {
"@T": "M",
"cPq7r": { "@T": "M", "v": "Date", "bl": 1 },
"cWm3s": { "@T": "M", "v": "Amount", "bl": 1 }
},
"r_Vn4wK7r": {
"@T": "M",
"cPq7r": {
"@T": "M",
"v": "2026-01-15",
"ct": { "@T": "M", "t": "t", "fa": "yyyy-mm-dd" }
},
"cWm3s": {
"@T": "M",
"v": 5200,
"ct": { "@T": "M", "t": "n", "fa": "#,##0" }
}
},
"r_Bt6yH2s": {
"@T": "M",
"cPq7r": {
"@T": "M",
"v": "2026-02-01",
"ct": { "@T": "M", "t": "t", "fa": "yyyy-mm-dd" }
},
"cWm3s": {
"@T": "M",
"v": 7800,
"ct": { "@T": "M", "t": "n", "fa": "#,##0" }
}
}
},
"merges": { "@T": "M" },
"borders": { "@T": "M" },
"hyperlinks": { "@T": "M" },
"validations": { "@T": "M" },
"conditionalFormats": ["@T:A"],
"hiddenRows": { "@T": "M" },
"hiddenCols": { "@T": "M" },
"rowHeights": { "@T": "M" },
"colWidths": { "@T": "M" },
"frozen": { "@T": "M" }
}
}
}
}In this example:
- Summary sheet (
aB3x_Qm7kL9p):- Header row with bold text, blue background, and centered alignment
- Product data with currency formatting (
$#,##0.00) - Formula cells computing totals (
=B2+C2,=B3+C3,=D2+D3) - “Grand Total” row with a merge spanning columns A-C and italic styling
- Medium blue bottom border on all header cells
- Custom column widths (150px for product name, 120px for data columns)
- Frozen first row (header stays visible while scrolling)
- Raw Data sheet (
Xk2nR8vH_wYq):- Simple 2-column table with date and amount data
- Date cells with
yyyy-mm-ddformat, number cells with thousands separator - No merges, borders, or custom sizing (all defaults)
- All
Y.Mapentries carry"@T": "M", arrays carry"@T:A", and sheet names areY.Textwith"@T": "T"