ESP32/Storage/35. Filesystem on flash
Your chip
Your language
Storage · 35 of 81

Filesystem on flash

There is a small disk inside the chip, and it behaves nothing like a disk. Files round up to 4 kB blocks, a reflash can wipe it, and the write that fails returns zero instead of raising anything.

/esp32/filesystem-on-flash · arduino · S3

A disk that charges by the block

The chip's flash has a region set aside for files. It is around 1.4 MB on a standard 4 MB board, and it is handed out in 4 kB blocks — so a 40-byte reading saved as its own file costs 4 kB, not 40 bytes.

LittleFS on the default 1.4 MB partition
17% used
Files60
Average file size3 kB
Real cost per file
4 kB
Partition used
17%
Wasted on padding
26%
244 kB of 1.4 MB, comfortably. Sizes like this are what the flash filesystem is for: a few HTML pages, a config file, a certificate. It is not a database, and it is not where a fast data logger should be writing — that is a microSD card.

LittleFS, not SPIFFS

SPIFFS is the older one, it has no directories, and it degrades badly when full. LittleFS is what to use for anything new: same API, real directories, and it survives power loss mid-write, which SPIFFS does not.

What belongs here, and what does not

Good: a web page and its CSS, a configuration file, a certificate, a calibration table. Things written rarely and read often.

Bad: a data logger sampling every second, anything larger than a megabyte, anything you would be upset to lose. Flash wears out at around 100,000 erases per block, and a reflash with a different partition scheme erases the lot. For data that matters, use a microSD card.

On your S3
ChipXtensa LX7 · 2 × 240 MHz
Board settingESP32S3 Dev Module
Default I2CSDA 8 · SCL 9
Watch out forThe port vanishes after upload

The code

Mount, append, read back. The two lines people leave out are the format-on-failure flag and the check on the write, and both of them are the difference between a logger and a device that has been silently discarding data.

littlefs_log.ino
#include <LittleFS.h>

void setup() {
  Serial.begin(115200);
  if (!LittleFS.begin(true)) {       // true = format if unmountable
    Serial.println("no filesystem");
    return;
  }

  File f = LittleFS.open("/log.csv", FILE_APPEND);
  if (!f) { Serial.println("open failed"); return; }

  size_t n = f.printf("%lu,%.2f\n", millis(), 21.4);
  if (n == 0) Serial.println("write failed - probably full");
  f.close();

  Serial.printf("%u of %u bytes used\n",
                LittleFS.usedBytes(), LittleFS.totalBytes());
}

void loop() {}

LittleFS.begin(true) formats the partition if it will not mount. Useful on a new board, dangerous later — it is how a firmware update quietly erases a customer's data.

When it does not work

Files vanish after uploading new firmware

The partition table moved. Changing the partition scheme in the IDE moves every boundary, and the filesystem region ends up somewhere else. Keep the scheme fixed for the life of a project.

Writes stop working and nothing reports an error

The partition is full. file.print returns the number of bytes written and everyone ignores it. Check usedBytes against totalBytes before a write, and check the return after.

It gets slower and slower over weeks

That is SPIFFS above about 80% full. It has no real garbage collection. LittleFS is the drop-in replacement and it also gives you directories.

A few hundred small files fill 1.4 MB

Not a bug. Every file occupies at least one 4 kB block. Append to one file rather than writing a file per reading.

Where this goes next

Mounting it is half the job. Getting your own files in there is a second, separate upload to a second, separate partition.

Uploading files to LittleFS

Edit this page — content/esp32/filesystem-on-flash.mdx

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse ESP32 on the forum