ESP32/Storage/37. Preferences and NVS
Your chip
Your language
Storage · 37 of 81

Preferences and NVS

A key-value store in flash that survives reboots and firmware updates. It looks like a dictionary, which is exactly why people write to it in a loop and wear the flash out in a fortnight.

/esp32/preferences-and-nvs · arduino · S3

How fast you can wear it out

1 save a minute
19.0 yr
Saves per minute1
Writes per day
72
Flash lasts
19.0 yr
19.0 yr — comfortably longer than the product. Reading is free; it is only the write that erases. Also worth knowing: NVS stores by key and type, so getInt("n") on a key you saved with putFloat returns the default and no error, which is an afternoon most people spend once.

What belongs in NVS

Settings, credentials, calibration constants, a device name, a boot counter. Small things, written rarely, read at startup.

Not: readings, logs, anything that accumulates. Those go to a file or a microSD card — and if they arrive faster than once a minute, they do not go in flash at all without a buffer in front of them.

The pattern worth copying

Read once at boot into a struct in RAM. Use the struct everywhere. Write back only on an actual change, or on a timer that batches several changes into one write. That turns a thousand writes a day into ten, which is the difference between a decade and a fortnight.

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

Open a namespace, read with a default, write only when the value changed. That last condition is the whole article - without it a setting saved every loop erases the flash on a schedule.

settings.ino
#include <Preferences.h>

Preferences prefs;
int setpoint = 21;

void save(int v) {
  prefs.begin("config", false);
  if (prefs.getInt("setpoint", -999) != v)     // only if it changed
    prefs.putInt("setpoint", v);
  prefs.end();
}

void setup() {
  Serial.begin(115200);
  prefs.begin("config", true);                 // true = read only
  setpoint = prefs.getInt("setpoint", 21);     // 21 is the default
  prefs.end();
  Serial.printf("setpoint %d\n", setpoint);
}

void loop() {}

The type must match. getInt on a key stored with putFloat returns the default and reports nothing, which is an afternoon most people spend exactly once.

When it does not work

The value comes back as the default every time

The type does not match what was stored, or the namespace name differs by a character. NVS reports neither - it just hands you the default.

put returns false and nothing is saved

The NVS partition is full or worn out. Erase it with nvs_flash_erase, and then look at how often you are writing.

Settings survive a firmware update that was meant to reset them

NVS is its own partition, so flashing an app does not touch it. Clearing it has to be deliberate.

A namespace name longer than 15 characters is rejected

That is the limit, and keys are capped at 15 too. Longer names fail at begin, quietly.

Where this goes next

When kilobytes are not enough. A card is gigabytes, an SPI bus, and a set of failure modes flash does not have.

microSD cards

Edit this page — content/esp32/preferences-and-nvs.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