---
title: 3.02.01. Penpot file format (.penpot)
desc: Complete technical specification for the .penpot file format, including structure, schemas, and inspection methods.
---

# Penpot File Format (.penpot)

The `.penpot` file format is Penpot's native export format for design files. It's a ZIP archive containing JSON metadata and binary assets, designed to be open, inspectable, and efficient.

## Overview

The `.penpot` format (version 3) uses a ZIP container with JSON files for metadata and binary files for media assets. This approach provides several advantages:

- **Open and inspectable**: All metadata is human-readable JSON
- **Efficient**: ZIP compression reduces file size
- **Interoperable**: Standard formats enable third-party tooling
- **Versioned**: Clear versioning system for format and data evolution

## Version History

| Version | Description | Status |
|---------|-------------|--------|
| v1 | Custom binary format | Deprecated |
| v2 | SQLite-based format | Never released (internal only) |
| v3 | ZIP + JSON format | **Current** |

## File Structure

A `.penpot` file contains the following structure:

```
pencil.penpot (ZIP archive)
├── manifest.json                          # Root metadata
├── files/
│   ├── {file-id}.json                     # File metadata
│   └── {file-id}/
│       ├── pages/
│       │   ├── {page-id}.json             # Page metadata
│       │   └── {page-id}/
│       │       └── {shape-id}.json        # Individual shapes
│       ├── media/
│       │   └── {media-id}.json            # Media references
│       ├── colors/
│       │   └── {color-id}.json            # Library colors
│       ├── components/
│       │   └── {component-id}.json        # Library components
│       ├── typographies/
│       │   └── {typography-id}.json       # Library typographies
│       ├── tokens.json                    # Design tokens library
│       └── thumbnails/
│           └── {tag}/{page-id}/{frame-id}.json  # Thumbnail metadata
└── objects/
    ├── {uuid}.json                        # Storage object metadata
    └── {uuid}.{ext}                       # Binary media files (png, jpg, etc.)
```

## Manifest Specification

The `manifest.json` file is the root of the archive and contains metadata about the export.

### Schema

```json
{
  "version": 1,
  "type": "penpot/export-files",
  "generatedBy": "penpot/2.12.0",
  "refer": "penpot",
  "files": [
    {
      "id": "uuid",
      "name": "File Name",
      "features": ["feature1", "feature2"]
    }
  ],
  "relations": []
}
```

### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `version` | integer | Yes | Format version (currently `1`) |
| `type` | string | Yes | Must be `"penpot/export-files"` |
| `generatedBy` | string | No | Penpot version that created the file |
| `refer` | string | No | Source system (typically `"penpot"`) |
| `files` | array | Yes | List of files in the archive |
| `files[].id` | UUID | Yes | File identifier |
| `files[].name` | string | Yes | File name |
| `files[].features` | array | Yes | Set of feature flags |
| `relations` | array | No | Library relationships `[file-id, library-id]` |

### Example

```json
{
  "type": "penpot/export-files",
  "version": 1,
  "generatedBy": "penpot/2.12.0-RC1-99-g40c27591f",
  "refer": "penpot",
  "files": [
    {
      "id": "73b59a94-3ea3-8189-8007-3d36adc8c3e3",
      "name": "Pencil | Penpot Design System",
      "features": [
        "fdata/path-data",
        "design-tokens/v1",
        "variants/v1",
        "layout/grid",
        "components/v2",
        "fdata/shape-data-type"
      ]
    }
  ],
  "relations": []
}
```

## File Metadata

Each file has a JSON file at `files/{file-id}.json` containing the file's metadata.

### Schema

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | UUID | Yes | File identifier |
| `name` | string | Yes | File name |
| `revn` | integer | Yes | Revision number |
| `vern` | integer | No | Version number |
| `createdAt` | timestamp | Yes | Creation timestamp |
| `modifiedAt` | timestamp | Yes | Last modification timestamp |
| `deletedAt` | timestamp | No | Deletion timestamp (if soft-deleted) |
| `projectId` | UUID | No | Project identifier |
| `teamId` | UUID | No | Team identifier |
| `isShared` | boolean | No | Whether file is a shared library |
| `hasMediaTrimmed` | boolean | No | Whether media has been trimmed |
| `features` | array | Yes | Set of enabled feature flags |
| `migrations` | array | No | List of applied data migrations |
| `options` | object | No | File-level options |

### Features

The `features` field is a set of strings indicating which features are enabled in the file. Common features include:

| Feature | Description |
|---------|-------------|
| `fdata/path-data` | Path data format |
| `fdata/shape-data-type` | Shape data type system |
| `design-tokens/v1` | Design tokens support |
| `variants/v1` | Component variants |
| `layout/grid` | Grid layout system |
| `components/v2` | Component system v2 |
| `plugins/runtime` | Plugin runtime support |

### Migrations

The `migrations` field lists all data migrations applied to the file. This ensures backward compatibility when the data model evolves.

### Example

```json
{
  "id": "73b59a94-3ea3-8189-8007-3d36adc8c3e3",
  "name": "Pencil | Penpot Design System",
  "revn": 28425,
  "vern": 0,
  "createdAt": "2025-12-10T10:24:18.686066Z",
  "modifiedAt": "2025-12-10T12:13:49.799076Z",
  "teamId": "b62e1aa4-d9a7-8147-8005-2813bed4056e",
  "projectId": "f23add0e-6b77-8069-8005-41b48b93a5da",
  "isShared": true,
  "features": [
    "fdata/path-data",
    "design-tokens/v1",
    "variants/v1",
    "layout/grid",
    "components/v2",
    "fdata/shape-data-type"
  ],
  "migrations": [
    "legacy-2",
    "legacy-3",
    "0001-remove-tokens-from-groups",
    "0002-normalize-bool-content-v2"
  ],
  "options": {
    "componentsV2": true
  }
}
```

## Pages and Shapes

### Page Structure

Each page is stored at `files/{file-id}/pages/{page-id}.json`.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | UUID | Yes | Page identifier |
| `name` | string | Yes | Page name |
| `index` | integer | No | Page order in the file |
| `options` | object | No | Page options (guides, etc.) |
| `background` | string | No | Background color (hex) |
| `flows` | object | No | Prototype flows |
| `guides` | object | No | Ruler guides |

### Shapes

Individual shapes are stored at `files/{file-id}/pages/{page-id}/{shape-id}.json`.

#### Shape Types

Penpot supports 9 shape types:

| Type | Description |
|------|-------------|
| `frame` | Container frame (artboard) |
| `group` | Group of shapes |
| `rect` | Rectangle |
| `circle` | Circle/Ellipse |
| `path` | Vector path |
| `text` | Text shape |
| `image` | Image |
| `bool` | Boolean operation |
| `svg-raw` | Raw SVG element |

#### Base Shape Attributes

All shapes share these base attributes:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | UUID | Yes | Shape identifier |
| `name` | string | Yes | Shape name |
| `type` | string | Yes | Shape type (see above) |
| `selrect` | object | Yes | Selection rectangle `{x, y, width, height}` |
| `points` | array | Yes | Array of points `[{x, y}, ...]` |
| `transform` | array | Yes | 2D transformation matrix |
| `transformInverse` | array | Yes | Inverse transformation matrix |
| `parentId` | UUID | Yes | Parent shape identifier |
| `frameId` | UUID | Yes | Containing frame identifier |

#### Geometry Attributes

Shapes with geometry (frame, rect, circle, image, svg-raw, text):

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `x` | number | Yes | X position |
| `y` | number | Yes | Y position |
| `width` | number | Yes | Width |
| `height` | number | Yes | Height |

#### Generic Attributes

Optional attributes available on all shapes:

| Field | Type | Description |
|-------|------|-------------|
| `fills` | array | Fill styles |
| `strokes` | array | Stroke styles |
| `opacity` | number | Opacity (0-1) |
| `blendMode` | string | Blend mode |
| `shadow` | array | Shadow effects |
| `blur` | object | Blur effect |
| `constraintsH` | string | Horizontal constraint |
| `constraintsV` | string | Vertical constraint |
| `r1`, `r2`, `r3`, `r4` | number | Border radius corners |
| `blocked` | boolean | Shape is locked |
| `hidden` | boolean | Shape is hidden |
| `collapsed` | boolean | Shape is collapsed |
| `componentId` | UUID | Component reference |
| `componentFile` | UUID | Component library file |
| `shapeRef` | UUID | Shape reference for components |
| `touched` | array | Modified component properties |
| `interactions` | array | Prototype interactions |
| `exports` | array | Export settings |
| `grids` | array | Grid configurations |
| `appliedTokens` | object | Applied design tokens |
| `pluginData` | object | Plugin-specific data |

#### Type-Specific Attributes

**Frame**
- `shapes`: array of child shape UUIDs
- `showContent`: boolean
- `hideInViewer`: boolean

**Group**
- `shapes`: array of child shape UUIDs

**Bool**
- `shapes`: array of child shape UUIDs
- `boolType`: string (`union`, `difference`, `exclude`, `intersection`)
- `content`: path data

**Path**
- `content`: path data (SVG path commands)

**Text**
- `content`: text content with formatting
- `positionData`: glyph position data

**Image**
- `metadata`: object with `width`, `height`, `mtype`, `id`

### Example Shape

```json
{
  "id": "260aea33-4e55-808c-8007-3d4f2efe4230",
  "name": "Rectangle",
  "type": "rect",
  "x": 100,
  "y": 100,
  "width": 200,
  "height": 150,
  "selrect": {
    "x": 100,
    "y": 100,
    "width": 200,
    "height": 150
  },
  "points": [
    {"x": 100, "y": 100},
    {"x": 300, "y": 100},
    {"x": 300, "y": 250},
    {"x": 100, "y": 250}
  ],
  "transform": [1, 0, 0, 1, 0, 0],
  "transformInverse": [1, 0, 0, 1, 0, 0],
  "parentId": "00000000-0000-0000-0000-000000000000",
  "frameId": "00000000-0000-0000-0000-000000000001",
  "fills": [
    {
      "color": "#FF5733",
      "opacity": 1
    }
  ],
  "r1": 8,
  "r2": 8,
  "r3": 8,
  "r4": 8
}
```

## Library Assets

### Colors

Stored at `files/{file-id}/colors/{color-id}.json`.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | UUID | Yes | Color identifier |
| `name` | string | Yes | Color name |
| `path` | string | No | Path in the library tree |
| `opacity` | number | No | Opacity (0-1) |
| `color` | string | Conditional | Hex color (for plain colors) |
| `gradient` | object | Conditional | Gradient definition |
| `image` | object | Conditional | Image fill definition |

#### Plain Color Example

```json
{
  "id": "abc123...",
  "name": "Primary Blue",
  "path": "Brand/Primary",
  "color": "#0066CC",
  "opacity": 1
}
```

#### Gradient Color Example

```json
{
  "id": "def456...",
  "name": "Sunset Gradient",
  "gradient": {
    "type": "linear",
    "startX": 0,
    "startY": 0,
    "endX": 1,
    "endY": 1,
    "stops": [
      {"color": "#FF6B6B", "offset": 0, "opacity": 1},
      {"color": "#4ECDC4", "offset": 1, "opacity": 1}
    ]
  }
}
```

### Components

Stored at `files/{file-id}/components/{component-id}.json`.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | UUID | Yes | Component identifier |
| `name` | string | Yes | Component name |
| `path` | string | Yes | Path in the library tree |
| `mainInstanceId` | UUID | Yes | Root shape of main instance |
| `mainInstancePage` | UUID | Yes | Page containing main instance |
| `modifiedAt` | timestamp | No | Last modification |
| `objects` | object | No | Captured shapes (if deleted) |

### Typographies

Stored at `files/{file-id}/typographies/{typography-id}.json`.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | UUID | Yes | Typography identifier |
| `name` | string | Yes | Typography name |
| `fontId` | string | Yes | Font identifier |
| `fontFamily` | string | Yes | Font family name |
| `fontVariantId` | string | Yes | Font variant |
| `fontSize` | string | Yes | Font size |
| `fontWeight` | string | Yes | Font weight |
| `fontStyle` | string | Yes | Font style |
| `lineHeight` | string | Yes | Line height |
| `letterSpacing` | string | Yes | Letter spacing |
| `textTransform` | string | Yes | Text transform |

### Design Tokens

Stored at `files/{file-id}/tokens.json`.

The tokens library contains:

- **Sets**: Collections of tokens organized hierarchically
- **Themes**: Named combinations of token sets
- **Active Themes**: Currently applied themes

#### Token Structure

```json
{
  "sets": {
    "core": {
      "id": "uuid",
      "name": "Core",
      "tokens": {
        "color": {
          "primary": {
            "id": "uuid",
            "name": "primary",
            "type": "color",
            "value": "#0066CC"
          }
        }
      }
    }
  },
  "themes": {
    "light": {
      "id": "uuid",
      "name": "Light",
      "sets": ["core"]
    }
  },
  "activeThemes": ["light"]
}
```

## Media and Storage Objects

### Storage Objects

Binary assets (images, fonts, etc.) are stored in the `objects/` directory.

Each storage object has:
- `objects/{uuid}.json` - Metadata
- `objects/{uuid}.{ext}` - Binary content (png, jpg, svg, etc.)

#### Metadata Schema

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | UUID | Yes | Storage object identifier |
| `size` | integer | Yes | File size in bytes |
| `contentType` | string | Yes | MIME type |
| `bucket` | string | Yes | Storage bucket |
| `hash` | string | No | Content hash (blake2b) |

#### Example

```json
{
  "id": "0039433d-adc8-430d-b2c3-d884dea6e050",
  "size": 575,
  "contentType": "image/png",
  "bucket": "file-media-object",
  "hash": "blake2b:77d447db38eb5daf31acb7344a504cacc6b79aa11855a00501d9475c595053d0"
}
```

### Media References

File media references are stored at `files/{file-id}/media/{media-id}.json`.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | UUID | Yes | Media identifier |
| `name` | string | Yes | File name |
| `width` | integer | Yes | Image width |
| `height` | integer | Yes | Image height |
| `mtype` | string | Yes | MIME type |
| `mediaId` | UUID | Yes | Reference to storage object |
| `thumbnaillId` | UUID | No | Reference to thumbnail |
| `isLocal` | boolean | No | Whether media is local to file |

### Thumbnails

Page thumbnails are stored at `files/{file-id}/thumbnails/{tag}/{page-id}/{frame-id}.json`.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `fileId` | UUID | Yes | File identifier |
| `pageId` | UUID | Yes | Page identifier |
| `frameId` | UUID | Yes | Frame identifier |
| `tag` | string | Yes | Thumbnail tag |
| `mediaId` | UUID | Yes | Reference to storage object |

## Plugin Data

Plugins can store custom data on files, pages, shapes, components, colors, and typographies using the `pluginData` field.

### Structure

```json
{
  "pluginData": {
    "plugin-id": {
      "key1": "value1",
      "key2": "value2"
    }
  }
}
```

The plugin ID is a keyword (e.g., `"my-plugin"`), and the values are string key-value pairs.

## Inspecting a .penpot File

### List Contents

```bash
unzip -l design.penpot
```

### Extract and View

```bash
# Extract to temporary directory
unzip design.penpot -d /tmp/penpot-inspect

# View manifest
cat /tmp/penpot-inspect/manifest.json | jq .

# List all files
find /tmp/penpot-inspect -name "*.json" | head -20

# View a specific shape
cat /tmp/penpot-inspect/files/*/pages/*/*.json | jq .
```

### Browser-Based Inspector

For an interactive way to explore a `.penpot` file, try the [**Penpot file inspector**](/technical-guide/developer/data-model/penpot-file-inspector/). It runs entirely in your browser, displays a collapsible file tree, syntax-highlighted JSON, image previews, and clickable cross-references between shapes, components, colors, and media.

### Quick Inspection Script

```bash
#!/bin/bash
# Inspect .penpot file structure

FILE=$1
TMPDIR=$(mktemp -d)

unzip -q "$FILE" -d "$TMPDIR"

echo "=== Manifest ==="
cat "$TMPDIR/manifest.json" | jq '{type, version, files: [.files[] | {id, name}]}'

echo -e "\n=== Files ==="
for f in "$TMPDIR"/files/*.json; do
  echo "- $(jq -r '.name' "$f")"
done

echo -e "\n=== Pages ==="
for f in "$TMPDIR"/files/*/pages/*.json; do
  echo "- $(jq -r '.name' "$f")"
done

echo -e "\n=== Storage Objects ==="
ls -lh "$TMPDIR"/objects/*.{png,jpg,svg} 2>/dev/null | wc -l
echo "media files"

rm -rf "$TMPDIR"
```

## Cross-References

- [Penpot file inspector](/technical-guide/developer/data-model/penpot-file-inspector/) - Browser-based interactive inspector
- [Data Model](/technical-guide/developer/data-model/) - Conceptual data model
- [Data Guide](/technical-guide/developer/data-guide/) - Working with data structures
- [Export/Import Files](/user-guide/export-import/export-import-files/) - User guide for exporting and importing

## Source Code References

The authoritative schema definitions are in the Penpot source code:

- **Manifest**: `backend/src/app/binfile/v3.clj` (schema:manifest)
- **File**: `common/src/app/common/types/file.cljc` (schema:file)
- **Page**: `common/src/app/common/types/page.cljc` (schema:page)
- **Shape**: `common/src/app/common/types/shape.cljc` (schema:shape)
- **Component**: `common/src/app/common/types/component.cljc` (schema:component)
- **Color**: `common/src/app/common/types/color.cljc` (schema:library-color)
- **Typography**: `common/src/app/common/types/typography.cljc` (schema:typography)
- **Tokens**: `common/src/app/common/types/tokens_lib.cljc` (schema:tokens-lib)
- **Plugin Data**: `common/src/app/common/types/plugins.cljc` (schema:plugin-data)
- **Features**: `common/src/app/common/features.cljc` (schema:features)
