Does ESP32
need PROGMEM?
Where It Came From
PROGMEM is an AVR thing. On older Arduino boards like the Uno and Pro Mini, the microcontroller has completely separate address spaces for flash and RAM. The CPU physically cannot read from flash like normal memory. If you declared a large array without PROGMEM, it had no choice but to live in RAM, eating into the tiny 2KB you had to work with. PROGMEM was the only way to keep data in flash and out of RAM on those chips.
Why It Keeps Showing Up
A huge amount of Arduino tutorial content was written for AVR boards and then carried forward unchanged into the ESP32 world. PROGMEM came with it. Nobody stopped to check whether it was still necessary.
What Happens on an ESP32
The ESP32 is not AVR. It can access flash transparently through a cache. When you declare a const array the compiler keeps it in flash without needing any hint from you. PROGMEM does not move the needle.
// These behave the same on ESP32
const uint8_t myArray[] = { 0x01, 0x02, 0x03 };
const uint8_t myArray[] PROGMEM = { 0x01, 0x02, 0x03 }; After testing with large arrays on real hardware - measuring free heap with and without PROGMEM - there was no measurable difference in RAM usage either way. The compiler was already doing the right thing.
What To Do
Declare your read-only arrays as const and let the compiler handle the rest. You can add PROGMEM if you want - it makes no difference on ESP32, it will not break anything. Same with pgm_read_byte(). Just use the array like normal either way.
const uint8_t myImage[] = { 0xFF, 0x00, 0x3A ... };
// Access it normally
uint8_t pixel = myImage[i]; The One Exception
If you are writing code that needs to run on both AVR and ESP32, PROGMEM and pgm_read_byte() are still the portable way to handle it. On ESP32 they do nothing harmful, and on AVR they are essential. In that specific case, keep them in.
For ESP32-only projects, leave them out.