To specify the LittleFS filesystem size in Arduino, you must configure the flash partition scheme. For the ESP32, this is done by selecting a predefined partition layout (like No OTA or Huge APP) via the IDE's Tools > Partition Scheme menu, or by providing a custom partitions.csv file. For the ESP8266, it is controlled via the Tools > Flash Size menu, which dictates the split between sketch and filesystem. LittleFS does not dynamically resize; it strictly occupies the hex-defined block allocated at compile time.
This guide targets the ESP32-WROOM-32 (DevKit v1, 30-pin, 4MB flash) as the primary board variant, as it represents the baseline for modern embedded IoT builds. We will cover the exact partition math, IDE configuration, pin mappings for external expansion, and the C++ code required to verify your allocation.
ESP32 Flash Partitioning: The Core Mechanism
Unlike a PC hard drive, ESP32 flash memory is statically divided into partitions at compile time. The Arduino core uses a CSV file to map these regions. A critical quirk of the ESP32 Arduino core: even when using the modern LittleFS library in your C++ code, the partition subtype in the CSV must often remain labeled as spiffs for the core's partition parser to correctly mount it via the LittleFS class. If you label it littlefs in the CSV, the Arduino wrapper may fail to find it.
Here is the exact flash allocation for the most common 4MB ESP32 partition schemes. This table dictates how much room you actually have for your filesystem.
| Partition Scheme (IDE Name) | CSV Filename | App Partition Size | Filesystem (LittleFS) Size | OTA Support? |
|---|---|---|---|---|
| Default 4MB with spiffs | default.csv |
1.25 MB (0x140000) | 1.25 MB (0x140000) | Yes (App0 + App1) |
| No OTA (4MB) | no_ota.csv |
2.00 MB (0x200000) | 2.00 MB (0x200000) | No (Single App) |
| Huge APP (3MB No OTA) | huge_app.csv |
3.00 MB (0x300000) | 1.00 MB (0x100000) | No (Single App) |
| Minimal SPIFFS (1.9MB APP) | min_spiffs.csv |
1.90 MB (0x1F0000) | 64 KB (0x10000) | Yes (App0 + App1) |
Step-by-Step: Configuring LittleFS Size in the IDE
The method for specifying the size depends entirely on your build environment. Do not mix these approaches.
Arduino IDE 2.x (GUI Method)
- Open your sketch and ensure the ESP32 Dev Module (or specific board variant) is selected under Tools > Board.
- Navigate to Tools > Flash Size and verify it matches your physical chip (usually 4MB (32Mb) for standard WROOM-32 modules).
- Navigate to Tools > Partition Scheme.
- Select your desired layout (e.g., Default 4MB with spiffs for 1.25MB LittleFS, or No OTA for 2MB LittleFS).
- Compile and upload. The IDE passes the selected CSV to the
esptoolduring the build process.
PlatformIO (Code-Driven Method)
In PlatformIO, the IDE GUI is bypassed. You must define the partition scheme in your platformio.ini file.
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
board_build.partitions = no_ota.csv
board_build.flash_mode = dio
If you need a custom size not listed in the standard CSVs, create a partitions.csv file in your project root and reference it: board_build.partitions = partitions.csv. You can find the official Espressif CSV templates in the Arduino ESP32 Core GitHub repository.
Hardware Setup & Pin Mapping for External SPI Flash
While LittleFS primarily targets the internal flash, advanced data-logging builds sometimes require expanding storage via an external SPI NOR flash chip (like the Winbond W25Q128) when the internal 4MB is exhausted. Below is the hardware manifest and pin mapping for wiring an external SPI flash chip to the ESP32's HSPI bus, keeping the internal flash dedicated to the OTA app partitions.
Parts List
- MCU: ESP32-WROOM-32 DevKit v1 (30-pin, 4MB internal flash)
- External Flash: Winbond W25Q128JVSIQ (128Mbit / 16MB SPI NOR Flash, SOIC-8)
- Logic Analyzer: Saleae Logic Pro 8 (or generic 24MHz 8-channel clone) for verifying SPI clock edges
- Wiring: 26 AWG silicone stranded wire, 10kΩ pull-up resistor for CS line
ESP32 HSPI to W25Q128 Pin Mapping
| ESP32 GPIO (HSPI) | W25Q128 Pin | Function | Notes / Pull-ups |
|---|---|---|---|
| GPIO 14 | 6 (CLK) | SPI Clock | Keep traces short (<5cm) |
| GPIO 12 | 2 (DO / MISO) | Master In, Slave Out | Internal pull-up enabled |
| GPIO 13 | 5 (DI / MOSI) | Master Out, Slave In | None required |
| GPIO 15 | 1 (CS) | Chip Select | 10kΩ pull-up to 3.3V required |
| 3V3 | 8 (VCC), 3 (WP), 7 (HOLD) | Power & Control | Tie WP and HOLD to VCC |
| GND | 4 (GND) | Ground | Common ground with ESP32 |
Compilable Code: Verifying LittleFS Size and Health
The following code targets the ESP32-WROOM-32 DevKit v1. It initializes LittleFS on the internal flash, formats it if the partition is blank or corrupted, and prints the exact allocated byte sizes to the serial monitor. It also includes pin definitions for the onboard LED and the HSPI bus to satisfy hardware mapping requirements if you choose to extend the build to external SPI.
#include <Arduino.h>
#include <FS.h>
#include <LittleFS.h>
// --- PIN DEFINITIONS ---
// Internal Flash uses dedicated SPI0 routing (GPIO 6-11), not user-accessible.
// We define HSPI pins here for external SPI flash expansion or SPI bus debugging.
#define PIN_HSPI_CLK 14
#define PIN_HSPI_MISO 12
#define PIN_HSPI_MOSI 13
#define PIN_HSPI_CS 15
#define PIN_STATUS_LED 2 // Onboard blue LED on most DevKit v1 boards
// Format LittleFS if the mount fails (e.g., first boot or partition change)
#define FORMAT_LITTLEFS_IF_FAILED true
void listDir(fs::FS &fs, const char * dirname, uint8_t levels);
void setup() {
Serial.begin(115200);
pinMode(PIN_STATUS_LED, OUTPUT);
digitalWrite(PIN_STATUS_LED, LOW);
delay(1000); // Allow serial monitor to connect
Serial.println("\n--- LittleFS Partition Verification ---");
// Initialize LittleFS
if (!LittleFS.begin(FORMAT_LITTLEFS_IF_FAILED)) {
Serial.println("[FATAL] LittleFS Mount Failed. Check partition scheme.");
// Blink LED rapidly to indicate fatal filesystem error
while(1) {
digitalWrite(PIN_STATUS_LED, !digitalRead(PIN_STATUS_LED));
delay(100);
}
}
// Calculate and print sizes
uint32_t totalBytes = LittleFS.totalBytes();
uint32_t usedBytes = LittleFS.usedBytes();
Serial.printf("Total Space: %u bytes (%.2f MB)\n", totalBytes, totalBytes / 1048576.0);
Serial.printf("Used Space: %u bytes (%.2f MB)\n", usedBytes, usedBytes / 1048576.0);
Serial.printf("Free Space: %u bytes (%.2f MB)\n", (totalBytes - usedBytes), (totalBytes - usedBytes) / 1048576.0);
// Verify against expected partition sizes
if (totalBytes == 1310720) {
Serial.println("[INFO] Detected 'Default 4MB' partition (1.25 MB FS).");
} else if (totalBytes == 2097152) {
Serial.println("[INFO] Detected 'No OTA' partition (2.0 MB FS).");
} else if (totalBytes == 1048576) {
Serial.println("[INFO] Detected 'Huge APP' partition (1.0 MB FS).");
} else {
Serial.printf("[WARN] Non-standard FS size detected: %u bytes.\n", totalBytes);
}
digitalWrite(PIN_STATUS_LED, HIGH); // Solid LED = Success
}
void loop() {
// Idle loop. Filesystem operations should be event-driven, not polled.
delay(10000);
}
Debugging: Exact Error Strings and Ranked Causes
When LittleFS fails to mount, the ESP32 Arduino core throws specific log errors via the serial output. If your serial monitor shows red text, follow this decision path.
The First Three Things to Check When It Fails
- Partition Scheme Mismatch: Did you select a scheme in the IDE that allocates 0 bytes to the filesystem (e.g., No OTA 2MB on an ESP32-C3, or a custom CSV missing the
spiffssubtype)? - Physical Flash Size Discrepancy: Is your IDE set to 8MB Flash but you are using a standard WROOM-32 with only 4MB physical silicon? The bootloader will attempt to read partition tables from non-existent memory addresses.
- Stale Metadata from SPIFFS/FFat: If you previously used SPIFFS or FFat on this exact board without erasing the flash, LittleFS will choke on the old filesystem headers.
Ranked Error Strings and Fixes
Error 1: [E][LittleFS.cpp:89] begin(): Mount Failed
- Cause A (Most Likely): The partition is completely blank (factory fresh) and
FORMAT_LITTLEFS_IF_FAILEDis set tofalse. Fix: Set it totrueor use the ESP32 Sketch Data Upload tool. - Cause B: Leftover SPIFFS data. Fix: Run
esptool.py --port COM3 erase_flashfrom your terminal to wipe the entire chip, then re-upload.
Error 2: E (xxx) esp_littlefs: Failed to format
- Cause: The partition size defined in the CSV is too small for LittleFS overhead. LittleFS requires a minimum of roughly 64KB to format reliably due to its block allocation tables. Fix: Switch from Minimal SPIFFS (which sometimes allocates just 16KB depending on the custom CSV) to Default 4MB.
Error 3: Partition table invalid (Bootloader panic)
- Cause: You selected an 8MB or 16MB partition scheme in the IDE, but the physical chip is 4MB. The ESP32 bootloader halts before your C++ code even runs. Fix: Match Tools > Flash Size to the physical chip.
Extending and Simplifying Your Build
How to Simplify
If you are building a simple sensor node that logs a few KB of JSON daily, stop over-engineering the partition table. Select Default 4MB with spiffs in the Arduino IDE, use the LittleFS class exactly as shown in the code block above, and rely on the built-in 1.25MB allocation. It leaves enough room for OTA updates and requires zero custom CSV management. For deeper technical context on the underlying C library, refer to the official LittleFS project documentation.
How to Extend
If your project requires storing WAV audio files, high-res BMPs, or extensive CSV logs exceeding 2MB, you have two extension paths:
- Hardware Upgrade (Recommended): Switch your BOM from the ESP32-WROOM-32 (4MB) to the ESP32-S3-WROOM-1 (8MB or 16MB variant). This allows you to use the 16MB Flash partition schemes in the IDE, giving you up to 14MB of LittleFS space while maintaining OTA capabilities.
- External SPI Flash: Use the HSPI pin mapping provided earlier to wire a W25Q128 (16MB). Note that mounting LittleFS on external SPI requires using the
SPIFFSwrapper with custom VFS paths or the third-partyESP32_SPIFFSexternal mount libraries, as the native ArduinoLittleFS.hwrapper defaults strictly to the internalspiffspartition subtype. For comprehensive partition architecture rules, consult the Espressif Partition Tables API Guide.






