Nano ESP32 pin numbering — the silkscreen Dn vs the chip's GPIO
Question this page answers: “Why does pinMode(2, OUTPUT) on the Nano ESP32 not drive GPIO2 — and which number should my code use?”
The board keeps the classic Nano silkscreen (D0-D13, A0-A7) so projects migrate between Nano generations without rewiring. But the ESP32-S3 behind those pins numbers its GPIOs differently: silkscreen D2 is GPIO5, D8 is GPIO17, and so on. What a bare number in your sketch means depends on one IDE setting.
The two numbering schemes
The Arduino board package offers two configurations (Tools > Pin Numbering):
| Setting | pinMode(2, OUTPUT) drives | Meant for |
|---|---|---|
| By Arduino pin (default) | the pin labelled D2 — physically GPIO5 | porting classic Nano sketches; wiring that follows the silkscreen |
| By GPIO number (legacy) | the chip’s GPIO2 — not brought out as “D2” | third-party ESP32 libraries that expect native GPIO numbers (OneWire, FastLED, ESP32Servo and friends) |
The D2-style labels are configuration-proof: pinMode(D2, OUTPUT) targets the physical D2 pin (GPIO5 inside) under either setting. That is the safest way to write portable code on this board.
Why this board needs the switch at all
Nano compatibility and ESP32 native numbering cannot both be true for bare numbers, so the board package makes it a choice. The official examples: with the default, pinMode(2, ...) configures the pin marked 2 on the board; with the GPIO option you would write pinMode(5, ...) for the same physical pin.
Third-party ESP32 libraries are the practical reason to switch: many take raw GPIO numbers and do not understand the Nano silkscreen, so under the default scheme they would silently drive the wrong pins.
The full map
The complete silkscreen-to-GPIO table (D0-D13, A0-A7, BOOT0/BOOT1) lives on the board page as part of the JP1/JP2 header mapping. A few pairs worth remembering:
- D0/D1 (serial RX/TX) — GPIO44/GPIO43
- A4/A5 (I2C SDA/SCL) — GPIO11/GPIO12
- D13 (built-in LED) — GPIO48
If a library misbehaves
Symptom: a sketch works on other ESP32 boards but drives the wrong pins here. That is the numbering trap, not a broken board — check which scheme the library assumes against the map, then align the setting or the pin arguments. For the general layers behind this (physical pin / silkscreen / GPIO / SDK name), see the pin numbers concept guide.
What this page cannot tell you
- We did not run these sketches on hardware here. The schemes, the switch and the label behavior are quoted from Arduino’s official pin-setup tutorial (fixed version below); the diagnostic order is MCUID’s editorial work.
- Numbering behavior outside the Arduino core. MicroPython support exists for this board, but how it names pins is not covered by the cited tutorial and is not asserted here.
- IDE walkthroughs. Menu paths drift between IDE versions; the official tutorial (updated by Arduino) is the reference for where the setting lives today.
Sources
- Arduino Nano ESP32 — Selecting Pin Configuration — the two schemes, the IDE switch,
Dnlabel behavior, the Nano↔ESP32 pin map, board package ≥ 2.0.12 (commitcb938e96) - Arduino Nano ESP32 datasheet — Pinout — JP1/JP2 header tables (commit
cb938e96)