Custom Partition Layouts
The partition table defines how the ESP’s flash memory is divided. The default layout works for simple applications, but OTA, large NVS storage, or filesystem partitions require a custom table. mcesptool provides tools to generate standard OTA layouts, define fully custom layouts, and analyze what is already on a device.
Default OTA layout
Section titled “Default OTA layout”The fastest way to get an OTA-capable partition table is esp_partition_create_ota:
esp_partition_create_ota({ "flash_size": "4MB", "app_size": "1MB"})This generates:
| Partition | Type | Subtype | Offset | Size |
|---|---|---|---|---|
| nvs | data | nvs | 0x9000 | 24KB |
| otadata | data | ota | 0xf000 | 8KB |
| phy_init | data | phy | 0x11000 | 4KB |
| ota_0 | app | ota_0 | 0x12000 | 1MB |
| ota_1 | app | ota_1 | 0x112000 | 1MB |
| storage | data | spiffs | 0x212000 | (remaining) |
Any space left after the two OTA slots is allocated to a SPIFFS storage partition.
Custom layouts
Section titled “Custom layouts”For layouts that do not fit the OTA template, use esp_partition_custom with a partition configuration dict.
Factory-only with large NVS
Section titled “Factory-only with large NVS”No OTA, but a large NVS partition for configuration storage:
esp_partition_custom({ "partition_config": { "partitions": [ { "name": "nvs", "type": "data", "subtype": "nvs", "size": "64K" }, { "name": "phy_init","type": "data", "subtype": "phy", "size": "4K" }, { "name": "factory", "type": "app", "subtype": "factory", "size": "2MB" }, { "name": "storage", "type": "data", "subtype": "spiffs", "size": "1MB" } ] }})OTA with LittleFS storage
Section titled “OTA with LittleFS storage”esp_partition_custom({ "partition_config": { "partitions": [ { "name": "nvs", "type": "data", "subtype": "nvs", "size": "24K" }, { "name": "otadata", "type": "data", "subtype": "ota", "size": "8K" }, { "name": "phy_init", "type": "data", "subtype": "phy", "size": "4K" }, { "name": "ota_0", "type": "app", "subtype": "ota_0", "size": "1536K" }, { "name": "ota_1", "type": "app", "subtype": "ota_1", "size": "1536K" }, { "name": "littlefs", "type": "data", "subtype": "littlefs", "size": "512K" } ] }})Dual-app with coredump
Section titled “Dual-app with coredump”A factory app plus one OTA slot, with a coredump partition for crash analysis:
esp_partition_custom({ "partition_config": { "partitions": [ { "name": "nvs", "type": "data", "subtype": "nvs", "size": "16K" }, { "name": "otadata", "type": "data", "subtype": "ota", "size": "8K" }, { "name": "phy_init", "type": "data", "subtype": "phy", "size": "4K" }, { "name": "factory", "type": "app", "subtype": "factory", "size": "1MB" }, { "name": "ota_0", "type": "app", "subtype": "ota_0", "size": "1MB" }, { "name": "coredump", "type": "data", "subtype": "coredump", "size": "64K" }, { "name": "storage", "type": "data", "subtype": "fat", "size": "512K" } ] }})Valid partition types and subtypes
Section titled “Valid partition types and subtypes”| Subtype | Value | Description |
|---|---|---|
factory | 0x00 | Factory application (default) |
ota_0 | 0x10 | OTA slot 0 |
ota_1 | 0x11 | OTA slot 1 |
ota_2 | 0x12 | OTA slot 2 |
ota_3 | 0x13 | OTA slot 3 |
test | 0x20 | Test application |
| Subtype | Value | Description |
|---|---|---|
ota | 0x00 | OTA selection data |
phy | 0x01 | PHY calibration data |
nvs | 0x02 | Non-volatile storage |
coredump | 0x03 | Core dump storage |
nvs_keys | 0x04 | NVS encryption keys |
efuse | 0x05 | eFuse emulation data |
fat | 0x81 | FAT filesystem |
spiffs | 0x82 | SPIFFS filesystem |
littlefs | 0x83 | LittleFS filesystem |
Alignment requirements
Section titled “Alignment requirements”If you provide explicit offsets in your partition entries, make sure app partitions fall on 64KB boundaries. The tool warns when auto-alignment shifts a partition’s offset.
Auto-calculated offsets
Section titled “Auto-calculated offsets”When you omit the offset field from a partition entry, the tool calculates it automatically. Partitions are laid out sequentially starting after the partition table region (offset 0x9000). Each partition starts immediately after the previous one ends, with app partitions rounded up to the next 64KB boundary.
To override auto-calculation for a specific entry, include an "offset" field:
{ "name": "storage", "type": "data", "subtype": "spiffs", "size": "1MB", "offset": "0x300000" }Convert CSV to binary
Section titled “Convert CSV to binary”Both esp_partition_create_ota and esp_partition_custom return a partition_csv field containing the generated CSV. To flash it to a device, you first need to convert it to the binary partition table format.
-
Save the CSV content to a file (e.g.,
partitions.csv). -
Convert using ESP-IDF’s partition generator:
Terminal window python $IDF_PATH/components/partition_table/gen_esp32part.py \partitions.csv partitions.bin -
Flash the binary to the partition table offset:
esp_flash_firmware({"port": "/dev/ttyUSB0","firmware_path": "partitions.bin","address": "0x8000"})
Analyze existing partition tables
Section titled “Analyze existing partition tables”To read and parse the partition table from a connected device:
esp_partition_analyze({ "port": "/dev/ttyUSB0"})The response lists every partition with its name, type, subtype, offset, size, and whether the encrypted flag is set. If the flash is blank (all 0xFF at the partition table offset), the response returns an empty partitions array.
This is useful for:
- Verifying a partition table was flashed correctly
- Inspecting an unknown device to understand its layout
- Finding the exact offset of a specific partition (e.g., otadata for manual rollback)