Skip to content

Saving

Octa supports writing for most formats it reads. Save semantics vary by format family; this page covers what to expect for each.

Quick reference

  • File → Save (Ctrl+S) writes back to the original path in the original format.
  • File → Save as… lets you pick a new path and / or a different format. The output format is chosen from the file extension you type in the save dialog. Afterwards it may ask a few things first, see Save as: the questions.
  • File → Save with password… writes the table into a password-protected zip (AES-256). See Password-protected files.
  • Closing a tab or quitting Octa with unsaved changes pops a "Save? Don't Save? Cancel?" confirmation.

The status bar shows a * next to the tab name when a tab has unsaved changes.

Saving a big table

A save of a big table (more than about half a million cells) runs in the background, so the window stays usable while the file is written:

  • The status bar shows which file is being saved.
  • That tab is read-only until the save is done, and sorting it waits too. The other tabs work as usual.
  • Octa hands the rows to the writer a slice at a time. For CSV, TSV and Parquet that is all the extra memory the save needs. Every other format (Excel, JSON and the rest) is written from a copy of the table put together in the background, so it needs about as much memory again as the table takes.
  • A backup and an earlier version of the file, when either is switched on, are copied in the background first. If that copy fails, nothing is written.
  • The file is replaced only once every row is written. If the table changes before then, for example because another file was opened into the tab, the save stops and the file stays as it was. Closing the tab stops the save the same way.
  • The tab counts as unsaved until the save is done, so quitting before then asks first, as for any unsaved tab.
  • Save in the close or quit question saves in the background too, and the tab closes, or Octa quits, once the save worked. If it fails, the tab stays open with its changes.

Saves into a SQLite, DuckDB or GeoPackage file change that file in place and are written while the window waits.

When the file changed underneath you

Octa remembers each open file's modification time and size, and checks them again before Save writes over that file.

If something else has rewritten the file since you opened it, a nightly job, an export, a colleague on a shared drive, Octa stops and asks rather than replacing their version with a snapshot taken before it existed:

  • Save anyway writes your version over the file, which is the right answer when you know your copy is the one that matters.
  • Reload throws away your unsaved edits and reads the file from disk again, the same as Ctrl+R.
  • Cancel touches nothing. The tab keeps your edits, so you can copy what you need out of it, or Save as to a second file and compare the two.

Only Save is guarded. Save as writes wherever you point it, because you just chose that path in the file dialog and the dialog asked about overwriting itself. A file that has been deleted is not a conflict either: saving recreates it.

Auto-save never raises this prompt. It skips a tab whose file changed and leaves the question for your next manual save.

When only part of the file is loaded

Octa stops reading at the initial-load row cap, so a very large file is open as a window onto itself. Save writes the rows it holds over the source path, which for such a file would delete every row that was never read, silently and with a success message.

So that one save asks first, naming the numbers:

  • Load all rows reads the whole file with the limit lifted, and then you save normally. On a big file that costs time and memory.
  • Save anyway writes only the loaded rows over the file. The rest is gone. This is right when you deliberately opened a slice.
  • Cancel touches nothing.

Save as asks too, before its file picker. It loses nothing from the source, but the new file would hold only the loaded rows: an 18 million row CSV saved as Parquet would quietly become a Parquet of its first 5 million. Load all rows and Cancel work as above; Save anyway goes on to the file picker and writes the slice. A large-file tab offers no Load all rows, since its rows stay on disk.

Rounding on save

Per-column number formats are display-only: the in-memory table keeps full precision. If you set a rounding format (fixed decimals) on any column and then Save or Save as, Octa asks how the file should be written:

  • Save rounded values writes the rounded numbers shown in the table.
  • Save full precision writes the original, un-rounded numbers.
  • Cancel aborts the save.

Either way the in-memory table stays at full precision, so the choice only affects the bytes on disk. Tabs without a rounding format save directly with no prompt.

What every Excel save carries

Four things go into every .xlsx Octa writes, whatever the formatting switch below says, because they are what makes a workbook usable rather than what makes it pretty:

  • Real dates. A date or timestamp column is written as an Excel date, not as text, so it sorts, filters and formats as a date in the spreadsheet. A value that cannot be parsed falls back to text rather than failing the save, so one piece of junk in a date column does not cost you the file.
  • Column widths. The widths you set on screen come across as they are. A save with no view behind it (the command line, the assistant, batch convert) uses Excel's autofit instead. A sheet over 500,000 rows is streamed to keep memory flat and keeps Excel's default widths.
  • A bold header row and a filter row. The header is bold and the data range gets an autofilter, so the drop-down arrows are there when the file opens.
  • Clickable links. A cell holding a bare http:// or https:// address is written as a hyperlink. Excel allows 65,530 links per sheet; past that the rest stay plain text, because a file over the limit will not open at all.

Data-validation rules come across too, as real Excel validation, so the workbook rejects bad input instead of only colouring it red in Octa. In range, Not empty and Max length have Excel equivalents; Matches pattern and Unique do not, and are skipped rather than approximated by something that would check a different thing.

Formatting in Excel files

Colour marks, conditional formatting colours, frozen columns and per-column number formats are display-only everywhere else, but .xlsx can hold all four. Carrying them across is off by default, since most saves are meant as plain data.

Turn it on under Settings → Files → Write options → Excel → Include formatting in Excel files. Independently of that switch, saving a tab that actually carries any of the four to .xlsx asks once:

  • Include formatting writes the colours, the frozen columns and the number formats into the workbook.
  • Plain data writes the values alone.
  • Do not ask again stores your answer as the Settings default, so later Excel saves go straight through.

Only .xlsx is affected. Every other format, .ods included, writes plain data and never asks.

This travels one way. Opening the saved workbook back in Octa reads the values alone: the reader does not import colours, frozen panes or number formats, so a round-trip through Octa loses them. The formatting is there for whoever opens the file in a spreadsheet.

What Excel cannot say the same way

Most conditional rules cross over as live Excel rules, which keep working when you edit the sheet in Excel. Three kinds cannot, and their colours are painted onto the cells matching today instead. A painted colour is a snapshot: it stays put when the cell changes in Excel.

  • Ordering comparisons over text (greater than, less than and so on with a non-numeric value). Excel orders text by locale collation, Octa by plain character order, so a live rule would colour different cells.
  • Case-sensitive equality or contains rules. Excel's own equality and SEARCH() are always case-insensitive, so a live rule would colour more cells than Octa does.
  • Every rule after the first painted one. Octa applies rules first-match-wins, but in Excel a live rule always beats a cell's own fill, with no notion of order between the two. Painting the remainder is what keeps the file agreeing with the screen. Rules before the first painted one stay live.

One further difference is accepted rather than engineered around: an equality rule whose value looks like a number exports as a numeric comparison, while Octa compares equality as text. A cell holding 42.0 against a rule value of 42 can therefore colour in Excel but not in Octa.

Write options

How a file is written is configurable, separately from what is written. The defaults live under Settings → Files → Write options and apply to every save, export and conversion, including command-line conversions that do not name --compression or --row-group-size explicitly. Batch Convert shows the same controls in its own Write options expander, where they apply to that run only.

Inside Write options the controls are grouped into one expander per format, Parquet, CSV / TSV and Excel, since no control applies to more than one of them. Open the group for the format you are writing.

Parquet is compressed with zstd unless you choose otherwise. Uncompressed Parquet is only about 1.6x smaller than the same data as CSV, where zstd reaches roughly 5x, and it costs about 1% more write time and 3% more read time. The File internals view reports the codec of any file you open, so you can check what you got.

Parquet write options

Option Default What it does
Compression zstd Codec for the file. zstd is the best size for the cost; uncompressed writes fastest and largest.
Rows per row group writer default Larger groups scan faster; smaller groups let readers skip more precisely.
Dictionary encoding on Stores repeated values once. Much smaller files when a column has few distinct values.
Column statistics on Writes min/max per chunk. Without them a query engine cannot skip row groups and reads everything.

CSV / TSV write options

These are the defaults for files written without the Save as window: the command line, batch convert and the SQL panel's export. Save as to a .csv asks instead, see Saving a CSV.

Option Default What it does
Delimiter the format's own Applies to CSV. Left at a comma, each file keeps the delimiter it was opened with; a .tsv writes tabs whatever this says.
Quoting only when needed Or quote every field, or suppress defensive quoting.
Line endings LF Switch to CRLF for consumers that require Windows line endings.
Header row on Turn off to write data only.
Decimal mark point Or comma (1234,56). A file opened with decimal commas keeps them either way.
Byte order mark off Start the file with the UTF-8 byte order mark. A file that had one keeps it either way.

Excel write options

Four switches, all off by default.

Include formatting in Excel files is covered in full under Formatting in Excel files above.

Keep Excel formulas when saving writes the formulas an .xlsx was read with back into the saved file, instead of the values Octa is showing. It is off by default for a reason worth knowing: Excel recalculates a formula when it opens the file, so the number in the saved workbook can end up different from the one you were looking at. Octa writes the value it has as the formula's cached result, so a tool that reads the file without evaluating formulas still sees the right number.

Two things retract a formula whatever this switch says, because keeping them would put a wrong answer in the file:

  • A cell you edited. Your value is what you meant; a formula that would recompute over it is no longer true.
  • A table whose rows or columns you moved, added or deleted. A formula says =B2*C2, and inserting a row changes what B2 points at. Octa cannot rewrite the references, so it drops every formula rather than keep ones that now mean something else.

Reading a formula needs no setting at all: hover a computed cell to see it, or open the Record view, which lists it beside the field.

Document properties stamps the workbook with a title (the file name) and Octa as the author. Off by default because it writes the file name into the file's own metadata, where it travels with the file to whoever you send it to.

Write as an Excel table writes the data as a real Excel table object instead of a plain range with a filter row, so the sheet gets a name, a structured reference and a table style. Off by default because a table style paints its own row banding, and that fights a conditional-format colour carried over from Octa; with the switch off the two never collide. The table replaces the autofilter rather than sitting on top of it.

Apart from the Parquet codec, which is zstd, the defaults reproduce exactly what Octa wrote before these options existed. Formats other than Parquet, CSV, TSV and .xlsx ignore them.

Save as uses the Settings defaults: it is the operating system's file picker, so there is nowhere to put per-save controls. Use Batch Convert (or the CLI flags below) when you want to override them for one run.

On the command line the same two Parquet knobs are --compression and --row-group-size, on both --convert and --batch-convert. Leaving them off uses these same Settings, so a conversion in the terminal writes the same file the app would. A machine with no settings file, such as a container or a CI runner, falls back to the built-in defaults.

File-format families

Text formats (CSV / TSV / JSON / JSONL / XML / TOML / YAML / Markdown / Plain Text)

Straightforward whole-file rewrite. The current table content replaces the file on disk.

  • CSV preserves the original delimiter it was opened with (comma / semicolon / pipe / tab), its decimal commas and its byte order mark. Octa detects them on open and reuses them on save.
  • TSV always uses tab.
  • JSON writes a pretty-printed array of objects keyed by column name.
  • JSONL writes one object per line.
  • Quote / escape behaviour for CSV is fixed RFC 4180 on write regardless of the Raw text view display options (those only affect viewing; see CSV Quote / Escape).

Columnar / data-science (Parquet / Arrow / Avro / ORC)

Whole-file rewrite with the table's current schema. Column types must round-trip through the format's type system; for unusual types Octa picks the closest match (most Decimal columns lose precision to Float64, for instance).

Parquet's compression and encoding choices use the defaults of the arrow+parquet crates.

Excel (.xlsx)

Whole-workbook rewrite via rust_xlsxwriter. The current table becomes the first (and only) worksheet.

Excel read supports .xlsx, .xls, .xlsm, .xlsb, .xlm (via calamine) and opens every sheet of a multi-sheet workbook (see Supported Formats). Excel write only emits .xlsx structure, since rust_xlsxwriter can't write the older formats. Save and Save as write the active tab as one sheet; to put several open tabs into one workbook, one sheet each, use File > Export workbook.... Save legacy workbooks as .xlsx to round-trip them through Octa.

.xlsx is the one format that can carry the table's on-screen formatting; see Formatting in Excel files.

OpenDocument Spreadsheet (.ods)

Whole-file rewrite. ODS is handled by Octa's dedicated ods_reader module: reads go through calamine, writes hand-roll a minimal OpenDocument Spreadsheet 1.2 package (mimetype + META-INF/manifest.xml

  • content.xml, zipped). Numbers and booleans are emitted with typed office:value/office:boolean-value attributes; everything else round-trips as strings.

The ODS writer carries less ceremony than .xlsx: no styles, no named ranges, no chart support. If you need those, save as .xlsx instead.

Statistical (SPSS / Stata)

Whole-file rewrite. SPSS uses ambers for write; Stata uses dta. Value labels, formats, and variable labels are preserved when they round-trip through DataTable's type system; missing-value codes become null.

DBF (dBase)

Whole-file rewrite. The DBF type system is more constrained than DataTable, so Octa rejects Binary columns up front (DBF has no generic binary type) and widens Int64 / UInt64 to wide Numeric because DBF Integer is i32.

Field names must be ≤ 10 ASCII bytes (DBF spec). Octa will fail the save with a clear error if a column name is too long; rename in Octa first.

Database files (SQLite / DuckDB / GeoPackage)

This is where the save story gets interesting. DB saves are diff-based, never overwrite.

On open, Octa snapshots:

  • Every row's rowid (SQLite) or synthetic __octa_row_id (DuckDB / GeoPackage).
  • Every row's original cell values.
  • The table's column schema.

On save:

  1. DELETE every original rowid missing from the current row_tags (i.e. rows the user deleted in Octa).
  2. INSERT every row whose tag is None (i.e. rows the user added in Octa).
  3. UPDATE only rows whose content differs from the original snapshot. Unchanged rows are skipped, not re-written.

All in one transaction.

Schema changes are rejected

DB save explicitly compares the current column names to the original column names. If they differ (a column was added, renamed, deleted, or reordered), the save fails with a clear error before touching the file.

To rename / add / drop a column in a SQLite or DuckDB table, open the database in another tool (or run an ALTER TABLE via Octa's SQL panel if you load the database via DuckDB-attach), then reopen the file in Octa.

This restriction protects downstream consumers from a column suddenly disappearing or being renamed.

The diff-on-save flow means:

  • Editing one cell in a 1M-row database table writes one UPDATE, not 1M.
  • New rows get auto-generated rowid / sequence values from the engine.
  • Deleted rows are remembered until save, and undo restores them including their original rowid.

For GeoPackage specifically, geometry columns round-trip through WKB. The Map view isn't wired to GeoPackage geometries yet; only GeoJSON triggers the Map view today.

Read-only formats

Format Why
SAS (.sas7bdat) sas7bdat 0.2 is read-only.
R Datasets (.rds, .rdata, .rda) rds2rust is read-only and Octa only handles the single data.frame case anyway.
HDF5 (.h5, .hdf5, .hdf) hdf5-reader 0.4 is read-only.
NetCDF v3 (.nc) netcdf3 0.6 is read-only in the upstream crate.
EPUB (.epub) Read-only by design; the EPUB reader view is a viewer.
GeoJSON (.geojson) Read-only for now; the Map view doesn't currently write back changes.

To export from a read-only format, use Save as… and pick a writable format (CSV, Parquet, etc.).

Save as across formats

File → Save as… routes through FormatRegistry: pick any file extension that Octa can write and the appropriate writer handles the conversion. Same as the CLI's octa --convert.

If you try to Save as into a read-only target (.sas7bdat, .rds, etc.), the dialog accepts the path but the save fails loudly with "format X does not support writing".

Save as: the questions

After you pick a file, Save as asks only what applies, all in one small window, and then writes:

  • Which rows should go into the file? Only while a text search or a column filter hides rows. All rows writes the whole table. Only the rows you see writes just the rows that match right now; the status bar then says "Exported N filtered rows to {path} (in-memory table unchanged)".
  • Open the new file after saving. On (the default), you carry on in the new file: the tab moves to it, or, when only the rows you see were saved, a new tab opens it. Off, the new file is only written, and the tab stays on its own file with its unsaved changes still unsaved.
  • How a CSV is written, for a .csv file. See Saving a CSV.

Both questions can be turned off under Settings > Files. Each has an Ask every time box and a choice next to it: untick the box and that choice is used without asking. Ticked, the choice is the answer the question starts at.

Regular Save (Ctrl+S) never asks and is unaffected by filters: it always writes the full table back to its own file, so a search or filter can never cost you rows on disk.

Saving a CSV

A CSV file is plain text with a separator between the values, and the program that opens it has to expect the same separator, or everything lands in one column. So a Save as to a .csv asks, in plain words:

Separator Who expects it
Comma The international standard. Most programs and websites expect it.
Semicolon Spreadsheet programs in Germany, France and most of Europe.
Tab A good choice when the values themselves contain commas or semicolons.
Vertical bar Some databases and data tools.

Below it you choose how decimal numbers look, 1234.56 or 1234,56, and whether spreadsheet programs should show accents correctly: that adds an invisible marker at the start of the file (the UTF-8 byte order mark) without which some spreadsheet programs on Windows show ä as ä. A preview shows the first lines exactly as they will be written. If a spreadsheet later shows everything in one column, the separator was the wrong one: save again with the other.

The choices start at the file's own when the tab was opened from a CSV, and otherwise at what is usual for your language (semicolon and decimal comma for the European languages Octa speaks). Only real numbers get the decimal comma; text that merely looks like a number is written exactly as it is. Choosing a comma for both the separator and the decimal mark is allowed, the numbers are then put in quotes, and the window says so.

A plain Save writes a CSV back the way it came: its separator, its decimal commas when Octa read its numbers the European way (1.234,56), and its byte order mark when it had one. A German CSV opened, edited and saved therefore stays a German CSV.

Unsaved-changes guards

Two checkpoints prevent accidental loss:

  1. Closing a tab with unsaved changes triggers a confirmation dialog (Save / Don't Save / Cancel).
  2. Closing the window (or quitting via menu) with any tab having unsaved changes triggers the same dialog, applied to all such tabs.

The Don't Save path discards every edit including structural changes. The undo stack is not preserved across reloads.

Exporting several tabs as one workbook

File > Export workbook... writes any number of open tabs into a single .xlsx, one worksheet per tab. Tick the tabs you want, adjust the sheet names if you like, and choose where to save.

Sheet names start from the tab labels and are editable, because a tab label can be long, repeated, or contain characters Excel refuses in a sheet name. Whatever you leave is corrected before writing: at most 31 characters, no forbidden punctuation, and duplicates numbered Report, Report_2. So the export cannot produce a workbook Excel will not open.

Chart tabs and empty tabs are not offered, since they have no table to write. The entry has no keyboard shortcut by default; assign one under Settings > Shortcuts if you use it often.

Headless, the same thing is --to-workbook (see the CLI overview):

octa --to-workbook report.xlsx sales.csv returns.parquet stock.json

Sheet names come from the file stems. Agents can do it with the write_workbook tool, which takes an explicit name per sheet.

Command line and MCP

The same job without the GUI:

See also