Skip to content

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.

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:

PartitionTypeSubtypeOffsetSize
nvsdatanvs0x900024KB
otadatadataota0xf0008KB
phy_initdataphy0x110004KB
ota_0appota_00x120001MB
ota_1appota_10x1120001MB
storagedataspiffs0x212000(remaining)

Any space left after the two OTA slots is allocated to a SPIFFS storage partition.

For layouts that do not fit the OTA template, use esp_partition_custom with a partition configuration dict.

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" }
]
}
})
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" }
]
}
})

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" }
]
}
})
SubtypeValueDescription
factory0x00Factory application (default)
ota_00x10OTA slot 0
ota_10x11OTA slot 1
ota_20x12OTA slot 2
ota_30x13OTA slot 3
test0x20Test application

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.

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" }

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.

  1. Save the CSV content to a file (e.g., partitions.csv).

  2. Convert using ESP-IDF’s partition generator:

    Terminal window
    python $IDF_PATH/components/partition_table/gen_esp32part.py \
    partitions.csv partitions.bin
  3. Flash the binary to the partition table offset:

    esp_flash_firmware({
    "port": "/dev/ttyUSB0",
    "firmware_path": "partitions.bin",
    "address": "0x8000"
    })

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)