Every hard cap in the SDK, in one place. These are compile-time constants in the firmware, not tunables — an app cannot raise them.

Display and input

Resource Limit
Frame text rows 7
Frame row width ~21 characters
Canvas (windowed) 128×48 pixels
Canvas (fullscreen) 128×64 pixels
Input return value 64 characters

Storage

Resource Limit
Open file handles 4 per session
KV key length 64 characters
KV value length 256 characters
IPC payload 512 bytes
File path length 160 characters

Wireless

Resource Limit
BLE scan results 20
BLE advertisement payload 31 bytes
BLE device name 32 characters
BLE simultaneous connections 2 per session
ESP-NOW payload 250 bytes
TCP listener 1
TCP accepted connections 2
TCP recv buffer 1024 bytes per call
HTTPS request body 2048 bytes

Apps and background

Resource Limit
Background tasks (device-wide) 8
Background task run quota 30 seconds
Background task minimum interval 60 seconds
Manifest capabilities 16
App pool — firmware v1.1 and earlier 64 KB
App pool — firmware exporting SDK level 3 80 KB

The app pool is a single workspace the firmware hands to one foreground activity at a time: a native app's binary (plus one loaded module), or a MicroPython app's GC heap. It is the one limit on this page that is not the same on every device — it grew from 64 KB to 80 KB alongside SDK level 3.

The pool size cannot be required from a manifest.

There is no sdk_min for it and no other way to say "needs 80 KB". An app built to fill the larger pool simply fails to load on v1.1 with NO_MEMORY. Size your binary or heap for 64 KB unless you control which firmware the device runs — or keep the resident part small and put the bulk in a module you load only when it fits.