An FCStd file is a standard ZIP archive. FreeCAD writes it with its own ZIP writer:
first Document.xml, then every data file that the XML asked for, in the
order it asked for them. The FreeCAD wiki describes the package briefly; this page
follows that description and the FreeCAD source code that writes and reads it
(src/App/Document.cpp, src/Base/Writer.cpp,
src/Base/Reader.cpp, src/Gui/Document.cpp and the property
classes), as of the main branch read in November 2026.
The ZIP container
| Item | Value | Meaning |
|---|---|---|
| Archive comment | FreeCAD Document | Set on every saved document |
| Compression level | 0 to 9, default 7 | The CompressionLevel preference, clamped to zlib’s range from no compression to best compression |
| Minimum size | 22 bytes | A file shorter than this is rejected as an invalid project file (an empty ZIP archive is 22 bytes) |
| First entry | Document.xml | Opened as the first entry of the ZIP stream and parsed before anything else |
FreeCAD saves to a temporary file first, named by adding a dot and a new UUID to the target name, and renames it over the real name once everything is written; the old file can be kept as a backup according to the backup preferences. A file can be unpacked with any ZIP tool, and the Std ProjectUtil command (Tools → Document utility) extracts and rebuilds packages; the wiki warns that the files inside are linked to each other, so editing one alone usually breaks the document.
Entry order
While Document.xml is written, each property that keeps its data
outside the XML registers a file name and puts that name in its XML element. The
names are collected in a list; after the XML is finished, the writer goes through
the list in order and writes each file as its own ZIP entry. Files registered while
a later file is being written (for example by view providers inside
GuiDocument.xml) are added to the end of the same list.
1Document.xml the document, its objects and their propertiesXML2StringHasher.Table.txt the document’s string table, when it is not emptytext3object data files shapes, meshes, lists and embedded files, in object ordervaries4GuiDocument.xml view providers and camera (only when the GUI is running)XML5thumbnails/Thumbnail.png preview image (GUI, when enabled)PNG6view provider data files registered while GuiDocument.xml was writtenvaries
When reading, FreeCAD parses Document.xml, which again registers the
files it needs, and then walks the remaining ZIP entries in order. Each entry is
matched against the next registered names; an entry nobody asked for is skipped,
and a registered file that is missing is simply not read. The source states that
the order of the files is kept, so a re-packed archive must keep
Document.xml first and the data files in the order the XML refers to
them. GuiDocument.xml is read in the same pass, and the files it
registers are read after it.
A document saved without the GUI (FreeCAD in console mode) has no
GuiDocument.xml and no thumbnail; when such a file is opened with the
GUI, the missing entry is not an error.
Entry names
| Entry name | Written by | Contents |
|---|---|---|
Document.xml | App document | See Document.xml and GuiDocument.xml |
GuiDocument.xml | GUI document | Display properties of every object and the camera |
thumbnails/Thumbnail.png | GUI thumbnail | PNG preview (below) |
StringHasher.Table.txt | Document string hasher | Table of hashed strings used for topological element names; starts with the line StringTableStart v1 count |
Object.Property.brp | Part shape property | OpenCASCADE BREP in text form, e.g. Box.Shape.brp |
Object.Property.bin | Part shape property | OpenCASCADE BREP in binary form, when binary BREP is switched on |
Object.Property.Map.txt | Part shape property | The shape’s topological element map (ElementMap2) |
Object.Property.Table.txt | Part shape property | A string table saved with the shape (SaveHasher) |
MeshKernel.bms | Mesh property | A mesh (Mesh::PropertyMeshKernel) |
| Property | List properties | Binary lists named after the property alone, e.g. a colour list (below) |
| original file name | App::PropertyFileIncluded | An embedded file, stored byte for byte under its own file name |
*.svg | TechDraw | Page templates, according to the wiki |
Object is the object’s internal name and Property the
property name, taken from the property’s full name after the document name. When a
name is already in use in the package, FreeCAD makes it unique by inserting digits
before the extension, where the extension is everything from the last dot. The
wiki’s older example shows the form PartShape.brp2; files from current
versions use the object and property names instead.
An embedded file’s name must be a plain file name: when it opens the document,
FreeCAD rejects any other name in a FileIncluded element as unsafe.
Shapes: text or binary BREP
Every Part shape property (Part::PropertyPartShape, the
Shape of Part and PartDesign objects) stores its solid in a separate
entry, so that a document can be opened without recomputing every feature. The
shape format is OpenCASCADE’s own BREP format; FreeCAD calls OpenCASCADE to write
and read it.
| Form | Chosen by | Extension | How FreeCAD writes it |
|---|---|---|---|
| Text BREP | Default | .brp | BRepTools_ShapeSet with format version 1, the shape set followed by the shape. With the Part preference DirectAccess off, it goes through a temporary file and starts with the line DBRep_DrawableShape |
| Binary BREP | Document preference SaveBinaryBrep (default off) | .bin | BinTools_ShapeSet with format version 3, followed by three 32-bit integers: the shape’s index in the set, its location index and its orientation; a null shape writes −1 three times |
An empty shape is stored as a zero-length entry. When reading, FreeCAD treats an
entry whose name ends in .bin as binary and anything else as text, so
both forms can appear in one document. The XML element that points to the entry is
described on the property types page;
when the writer is set to XML-only output, the same shape is written inside the XML
instead, as text in a CDATA section or binary as Base64.
Thumbnail
| Item | Value |
|---|---|
| Entry | thumbnails/Thumbnail.png |
| Written when | The GUI is running and the SaveThumbnail preference is on (the default) |
| Size | Square, ThumbnailSize pixels: default 256, clamped to 64–512 |
| Rendering | The whole scene fitted into an orthographic camera in the default orientation, transparent background; if no 3D view is available, the existing thumbnail of the saved file is reused |
The wiki describes the thumbnail as 128 × 128 pixels in
Thumbnails/thumbnail.png; the current source writes the size above and
the name with a lower-case folder and capital T.
Binary list files
List properties that can be long store a file attribute in the XML and
their values in an entry named after the property. Every such file starts with a
32-bit unsigned count. Numbers are written without byte swapping by FreeCAD’s
stream class, whose default order it calls little-endian. All floating-point lists
are written as 64-bit doubles: the single-precision option is obsolete and always
off.
| XML element | Property type | Each item after the count |
|---|---|---|
FloatList | App::PropertyFloatList | double |
VectorList | App::PropertyVectorList, also Mesh normals | x, y, z as doubles |
PlacementList | App::PropertyPlacementList | Px, Py, Pz, Q0, Q1, Q2, Q3 as doubles (position, then the rotation quaternion) |
ColorList | App::PropertyColorList | uint32 packed colour 0xRRGGBBAA |
MaterialList (version="3") | App::PropertyMaterialList | See below |
FilletEdges | Part::PropertyFilletEdges | int32 edge number, then radius 1 and radius 2 as doubles |
A MaterialList file in version 3 holds the count, then for every
material four packed colours (ambient, diffuse, specular, emissive, each uint32
0xRRGGBBAA) and two 32-bit floats (shininess and transparency), and
then, after all materials, three strings per material: image, image path and UUID.
Each string is a uint32 length followed by that many bytes.
version attribute | File layout read |
|---|---|
| 3 | As above |
| 2 | Count, then the colours and floats only (no strings) |
| absent | A signed 32-bit number first: if negative (files from development builds), the count follows; otherwise it is the count. Colours and floats only |
The meaning of alpha changed in FreeCAD 1.1. When the document’s
ProgramVersion is older than 1.1, FreeCAD inverts the alpha byte of
every colour it reads from ColorList, MaterialList,
PropertyColor and PropertyMaterial, so files from older
versions store transparency where newer ones store opacity.
The mesh entry MeshKernel.bms, the mesh CurvatureList and
Material files, the element map and string table text files have their
own layouts, which this reference does not describe.
Not confirmed
- The exact backup file names: the source shows the preferences
(
CreateBackupFiles,CountBackupFiles,UseFCBakExtension,SaveBackupDateFormat) but the naming code was not read. - Whether ZIP entries are stored or deflated at level 0, and any ZIP feature (such as ZIP64 or data descriptors) the writer may use: the ZIP writer library was not read.
- The byte order a big-endian machine would write in the binary list files.
- The layouts of
MeshKernel.bms, the element map and string table files.
Sources
- File Format FCStd – FreeCAD wiki, read from the FreeCAD-documentation repository’s
wiki/File_Format_FCStd.md - Std ProjectUtil – FreeCAD wiki, from the same repository
- FreeCAD source code – main branch:
src/App/Document.cpp(saving, reading, compression and comment),src/Base/Writer.cppandWriter.h(file list, unique names),src/Base/Reader.cpp(reading order),src/Base/Stream.cpp,src/Gui/Document.cppandsrc/Gui/Thumbnail.cpp,src/Mod/Part/App/PropertyTopoShape.cppandTopoShape.cpp(BREP),src/App/PropertyStandard.cpp,PropertyGeo.cpp,PropertyFile.cpp,Property.cpp,StringHasher.cppandComplexGeoData.cpp