The Arduino Nano ESP32 has one pin-numbering feature that can confuse even experienced ESP32 users.
The pin printed on the board is not always the number you would normally use on an ESP32-S3 development board.
For example:
|
1 2 3 4 5 6 |
All three descriptions refer to the same physical pin.
Arduino solves this by offering two pin-numbering modes:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
Tools → Pin Numbering → By Arduino pin (default) or Tools → Pin Numbering → By GPIO number (legacy) |
The most important rule is simple:
|
1 2 3 4 5 6 7 |
Use D2, D10, A0, A4, SDA, SCL, MOSI, MISO, SCK, etc. Avoid bare numbers such as 2, 5, 10 or 21 unless you deliberately know which numbering mode is selected. |
Why Nano ESP32 Numbering Is Different
Traditional Arduino Nano boards use a familiar numbering scheme:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
D0 D1 D2 ... D13 A0 A1 ... A7 |
Normal ESP32 development boards usually expose raw Espressif GPIO numbers:
|
1 2 3 4 5 6 7 8 9 |
GPIO1 GPIO2 GPIO5 GPIO6 GPIO7 ... |
Arduino wanted Nano ESP32 to remain compatible with the Nano form factor while still exposing the underlying ESP32-S3 hardware.
The result is a translation layer between:
|
1 2 3 4 5 6 |
Arduino Nano label and native ESP32-S3 GPIO |
Complete Nano ESP32 Pin Mapping
| Board label | Arduino pin number | Native ESP32-S3 GPIO | Main default function |
|---|---|---|---|
| D0 | 0 | GPIO44 | RX |
| D1 | 1 | GPIO43 | TX |
| D2 | 2 | GPIO5 | GPIO / ADC1 |
| D3 | 3 | GPIO6 | GPIO / ADC1 / CTS |
| D4 | 4 | GPIO7 | GPIO / ADC1 / DSR |
| D5 | 5 | GPIO8 | GPIO / ADC1 |
| D6 | 6 | GPIO9 | GPIO / ADC1 |
| D7 | 7 | GPIO10 | GPIO / ADC1 / I2S SCK |
| D8 | 8 | GPIO17 | GPIO / ADC2 / I2S FS |
| D9 | 9 | GPIO18 | GPIO / ADC2 / I2S data |
| D10 | 10 | GPIO21 | SS / CS |
| D11 | 11 | GPIO38 | MOSI / COPI |
| D12 | 12 | GPIO47 | MISO / CIPO |
| D13 | 13 | GPIO48 | SCK / LED_BUILTIN |
| A0 | 17 | GPIO1 | ADC1_CH0 |
| A1 | 18 | GPIO2 | ADC1_CH1 |
| A2 | 19 | GPIO3 | ADC1_CH2 |
| A3 | 20 | GPIO4 | ADC1_CH3 |
| A4 | 21 | GPIO11 | SDA / ADC2_CH0 |
| A5 | 22 | GPIO12 | SCL / ADC2_CH1 |
| A6 | 23 | GPIO13 | ADC2_CH2 |
| A7 | 24 | GPIO14 | ADC2_CH3 |
What “By Arduino Pin” Means
This is the default Nano ESP32 mode.
In this mode:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
0 → D0 → GPIO44 1 → D1 → GPIO43 2 → D2 → GPIO5 ... 13 → D13 → GPIO48 |
So this sketch:
|
1 2 3 4 5 |
pinMode(2, OUTPUT); digitalWrite(2, HIGH); |
does not mean GPIO2.
It means:
|
1 2 3 4 5 6 |
Arduino pin 2 → D2 → ESP32-S3 GPIO5 |
What “By GPIO Number” Means
If you select:
|
1 2 3 4 5 6 |
Tools → Pin Numbering → By GPIO number (legacy) |
bare integers are interpreted as native ESP32-S3 GPIO numbers.
So:
|
1 2 3 4 |
pinMode(5, OUTPUT); |
means:
|
1 2 3 4 5 |
GPIO5 → physical Nano pin D2 |
rather than Nano pin D5.
The Same Number Can Mean Two Different Physical Pins
This is the key problem.
Consider:
|
1 2 3 4 |
digitalWrite(5, HIGH); |
Arduino-pin mode
|
1 2 3 4 5 6 |
5 → D5 → GPIO8 |
GPIO-number mode
|
1 2 3 4 5 6 |
5 → GPIO5 → D2 |
The exact same source code controls a different physical pin.
Use Symbolic Pin Names Instead
This code is safe:
|
1 2 3 4 5 |
pinMode(D5, OUTPUT); digitalWrite(D5, HIGH); |
because D5 resolves correctly under either numbering mode.
In Arduino mode:
|
1 2 3 4 5 6 7 |
D5 → Arduino pin 5 → mapping layer → GPIO8 |
In GPIO mode:
|
1 2 3 4 5 |
D5 → GPIO8 |
Either way, the same physical D5 pin is used.
This Is the Recommended Coding Style
Use:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
D0 D1 D2 ... D13 A0 A1 ... A7 SDA SCL SS MOSI MISO SCK LED_BUILTIN |
rather than:
|
1 2 3 4 5 6 7 |
0 1 2 ... |
for board-level code.
Why ESP32 Libraries Sometimes Break on Nano ESP32
Many libraries written for generic ESP32 boards assume:
|
1 2 3 4 5 6 |
pin number = native GPIO number |
For example, a library may expect:
|
1 2 3 4 5 |
5 → GPIO5 |
but in Nano ESP32’s default Arduino mode:
|
1 2 3 4 5 6 |
5 → D5 → GPIO8 |
This can cause:
- displays not initialising;
- SPI chip-select failures;
- wrong interrupt pins;
- motors or LEDs responding on unexpected pins;
- boot problems if the wrong native GPIO is driven.
When to Use GPIO-Number Mode
GPIO-number mode can be useful when:
- porting an existing ESP32-S3 project;
- using a library that expects raw GPIO numbers;
- following Espressif documentation directly;
- working deeply with ESP-IDF APIs;
- you want the code to match native ESP32 terminology.
But even in GPIO-number mode, symbolic Nano names still work.
When to Keep the Default Arduino-Pin Mode
Keep the default when:
- you are writing a new Arduino sketch;
- you want Nano-family portability;
- you are following Arduino examples;
- you use Nano carrier boards;
- you want code to match the silkscreen.
For most users, there is little reason to change the default.
UART Pin Mapping
The default external serial pins are:
|
1 2 3 4 5 6 7 8 9 10 |
D0 → GPIO44 → RX D1 → GPIO43 → TX |
Use:
|
1 2 3 4 |
Serial1 |
for the external UART while the USB serial connection uses the board’s native USB stack.
Why D0 Is Not GPIO0
This is perhaps the most visually confusing example.
On many ESP32 examples:
|
1 2 3 4 |
GPIO0 |
has boot-related significance.
On Nano ESP32:
|
1 2 3 4 5 6 7 8 |
D0 ≠ GPIO0 D0 = GPIO44 |
Native:
|
1 2 3 4 |
GPIO0 |
is instead connected internally to the RGB LED path and other board functions.
SPI Pin Mapping
The Nano-compatible default SPI mapping is:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
D10 → GPIO21 → SS / CS D11 → GPIO38 → MOSI / COPI D12 → GPIO47 → MISO / CIPO D13 → GPIO48 → SCK |
The safe code is:
|
1 2 3 4 5 6 |
SPI.begin(); digitalWrite(SS, LOW); |
or explicitly use:
|
1 2 3 4 5 6 7 |
D10 D11 D12 D13 |
Do Not Copy Generic ESP32 SPI Pin Numbers Blindly
A common ESP32 example may use something like:
|
1 2 3 4 5 6 7 |
18 23 19 5 |
for SCK, MOSI, MISO and CS.
Those numbers originate from older generic ESP32 board conventions.
They are not the Nano ESP32 default SPI header mapping.
I²C Pin Mapping
The default Nano I²C bus is:
|
1 2 3 4 5 6 7 8 9 10 |
A4 → GPIO11 → SDA A5 → GPIO12 → SCL |
Use:
|
1 2 3 4 |
Wire.begin(); |
and libraries will normally use the correct pins automatically.
I²C Can Be Remapped
ESP32-S3’s GPIO matrix allows I²C signals to be assigned to many available GPIOs.
But Arduino chose:
|
1 2 3 4 |
A4 / A5 |
as the defaults for Nano compatibility.
Many libraries assume those defaults, so remap only when necessary.
Analog Pin Mapping
The analog header has another useful split.
| Nano label | Native GPIO | ADC unit/channel |
|---|---|---|
| A0 | GPIO1 | ADC1_CH0 |
| A1 | GPIO2 | ADC1_CH1 |
| A2 | GPIO3 | ADC1_CH2 |
| A3 | GPIO4 | ADC1_CH3 |
| A4 | GPIO11 | ADC2_CH0 |
| A5 | GPIO12 | ADC2_CH1 |
| A6 | GPIO13 | ADC2_CH2 |
| A7 | GPIO14 | ADC2_CH3 |
A0 Is Not “Pin 0”
In the default Arduino numbering layer:
|
1 2 3 4 5 6 |
A0 → Arduino pin 17 → GPIO1 |
So:
|
1 2 3 4 |
analogRead(A0); |
is the correct portable form.
Avoid:
|
1 2 3 4 |
analogRead(17); |
because that literal changes meaning if GPIO-number mode is enabled.
ADC1 vs ADC2
Nano ESP32 maps:
|
1 2 3 4 5 6 7 8 |
A0-A3 → ADC1 A4-A7 → ADC2 |
ESP32 wireless operation can impose more constraints on ADC2 resources than ADC1.
For analog measurements during heavy Wi-Fi use, A0-A3 are generally the safer first choice.
Digital Pins Can Also Be Analog Inputs
The official Nano ESP32 pinout exposes ADC capability on several D pins as well.
For example:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
D2 → GPIO5 → ADC1_CH4 D3 → GPIO6 → ADC1_CH5 D4 → GPIO7 → ADC1_CH6 D5 → GPIO8 → ADC1_CH7 D6 → GPIO9 → ADC1_CH8 D7 → GPIO10 → ADC1_CH9 |
and:
|
1 2 3 4 5 6 7 8 9 10 |
D8 → GPIO17 → ADC2_CH6 D9 → GPIO18 → ADC2_CH7 |
This is useful when the normal A0-A7 header is already occupied.
Built-In LED Mapping
The classic built-in single LED is:
|
1 2 3 4 5 6 |
LED_BUILTIN → D13 → GPIO48 |
So this works regardless of numbering mode:
|
1 2 3 4 5 |
pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); |
RGB LED Mapping
The current Arduino-ESP32 Nano variant defines:
|
1 2 3 4 5 6 7 8 9 10 11 |
LED_RED → GPIO46 LED_GREEN → GPIO0 LED_BLUE → GPIO45 |
Use the symbolic names:
|
1 2 3 4 5 6 |
LED_RED LED_GREEN LED_BLUE |
rather than hard-coding their software pin numbers.
Arduino’s hardware documentation also notes that some early limited-production boards used a different RGB LED arrangement with green and blue inverted.
Why Symbolic RGB Names Are Especially Important
Board revisions and core definitions can hide hardware details.
Your code should express:
|
1 2 3 4 |
LED_GREEN |
rather than:
|
1 2 3 4 5 6 7 |
0 15 16 45 |
depending on assumptions about numbering mode or board revision.
Native USB Pins Are Not Normal Header GPIO
ESP32-S3 native USB uses:
|
1 2 3 4 5 6 7 8 |
GPIO19 → USB D- GPIO20 → USB D+ |
on Nano ESP32.
These signals are connected to the USB-C interface and are not part of the normal D0-D13/A0-A7 header set.
Do not treat GPIO19/20 as spare generic header pins when using USB.
Internal Flash and PSRAM Also Consume ESP32-S3 Pins
Nano ESP32 uses the NORA-W106 module with:
- 16 MB Flash;
- 8 MB PSRAM.
Some ESP32-S3 GPIOs are therefore used internally by the module memory interface and are not available on the Nano headers.
This is another reason generic ESP32-S3 pinout diagrams should not be applied blindly to Nano ESP32.
Not Every ESP32-S3 GPIO Exists on the Nano Header
The ESP32-S3 has many GPIO numbers, but Nano ESP32 exposes only the subset needed for its Nano-compatible layout.
A generic example that says:
|
1 2 3 4 |
use GPIO35 |
does not mean that GPIO35 is available on the Nano ESP32 header.
Always check the Nano-specific pinout.
Interrupts
Arduino documents all exposed Nano ESP32 GPIO as interrupt-capable.
Use:
|
1 2 3 4 5 6 7 8 |
attachInterrupt( digitalPinToInterrupt(D2), handler, RISING ); |
Again, symbolic pin names avoid numbering-mode bugs.
PWM
ESP32-S3 PWM uses the LEDC peripheral and can be routed to many GPIOs.
When assigning PWM pins, use:
|
1 2 3 4 5 6 7 |
D3 D5 D9 A1 |
or whatever labelled pin you have chosen.
Do not convert to a raw GPIO unless the library specifically requires it.
Touch-Capable GPIOs
ESP32-S3 supports capacitive touch on a subset of GPIOs.
On Nano ESP32, touch capability is exposed through pins whose underlying native GPIO supports the touch peripheral.
If a library accepts raw ESP32 GPIO numbers, translate the Nano label using the mapping table before configuring touch input.
What Happens Inside the Arduino Core?
The Nano ESP32 variant file contains two alternative definitions.
In Arduino-pin mode, symbols are assigned Nano-style numbers:
|
1 2 3 4 5 6 7 8 9 |
D0 = 0 D1 = 1 D2 = 2 ... A0 = 17 A7 = 24 |
The core then remaps those numbers to the actual ESP32-S3 GPIO.
In GPIO-number mode, the same symbols are defined directly as:
|
1 2 3 4 5 6 7 8 9 |
D0 = 44 D1 = 43 D2 = 5 ... A0 = 1 A7 = 14 |
That is why symbolic names work in both modes.
Example: D2 in Both Modes
Arduino-pin mode
|
1 2 3 4 5 6 7 8 |
constexpr D2 = 2 digitalWrite(D2, HIGH); → remap Arduino pin 2 → GPIO5 |
GPIO-number mode
|
1 2 3 4 5 6 7 |
constexpr D2 = 5 digitalWrite(D2, HIGH); → direct GPIO5 |
The application source code does not change.
Example: Why Bare 2 Is Dangerous
Arduino-pin mode
|
1 2 3 4 5 6 |
digitalWrite(2, HIGH); → D2 → GPIO5 |
GPIO-number mode
|
1 2 3 4 5 6 |
digitalWrite(2, HIGH); → GPIO2 → A1 |
So switching the IDE option silently moves the output from D2 to A1.
Example: Why Bare 10 Is Dangerous
Arduino-pin mode
|
1 2 3 4 5 6 |
10 → D10 → GPIO21 |
GPIO-number mode
|
1 2 3 4 5 6 |
10 → GPIO10 → D7 |
A library using literal pin 10 as SPI CS could therefore change physical pins when the numbering option changes.
Best Practice for Libraries
If you are writing a library intended to support Nano ESP32, accept a pin value from the sketch rather than assuming a raw GPIO.
Good application code:
|
1 2 3 4 |
MyDevice dev(D10); |
Less portable application code:
|
1 2 3 4 |
MyDevice dev(21); |
unless the library explicitly documents that it requires native ESP32 GPIO numbers.
How to Port Generic ESP32-S3 Code to Nano ESP32
Suppose an ESP32-S3 example contains:
|
1 2 3 4 5 |
#define CS_PIN 21 #define IRQ_PIN 5 |
Do not assume those are Nano pin numbers.
If the source means raw ESP32 GPIO:
|
1 2 3 4 5 6 7 8 |
GPIO21 → Nano D10 GPIO5 → Nano D2 |
Rewrite the Nano version as:
|
1 2 3 4 5 |
#define CS_PIN D10 #define IRQ_PIN D2 |
This makes the intent explicit and protects the sketch from numbering-mode changes.
How to Find the Nano Label for a Raw ESP32 GPIO
Use the mapping table in reverse.
Examples:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
GPIO44 → D0 GPIO43 → D1 GPIO5 → D2 GPIO21 → D10 GPIO38 → D11 GPIO47 → D12 GPIO48 → D13 GPIO1 → A0 GPIO11 → A4 GPIO14 → A7 |
How to Find the Raw GPIO for a Nano Label
Examples:
|
1 2 3 4 5 6 7 8 9 10 11 |
D0 → GPIO44 D2 → GPIO5 D7 → GPIO10 D10 → GPIO21 D13 → GPIO48 A0 → GPIO1 A4 → GPIO11 A7 → GPIO14 |
Recommended Style for New Nano ESP32 Projects
Prefer code like:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
constexpr uint8_t BUTTON_PIN = D2; constexpr uint8_t CS_PIN = D10; constexpr uint8_t SENSOR_PIN = A0; void setup() { pinMode(BUTTON_PIN, INPUT_PULLUP); pinMode(CS_PIN, OUTPUT); } void loop() { int sensor = analogRead(SENSOR_PIN); } |
This is clear, readable and independent of the selected pin-numbering mode.
Common Mistake 1: Copying ESP32 DevKit Pin Numbers
You find an example online:
|
1 2 3 4 5 |
SDA = 21 SCL = 22 |
and paste it into Nano ESP32.
That is a generic ESP32 convention, not the Nano ESP32 default.
Nano ESP32 uses:
|
1 2 3 4 5 |
SDA = A4 = GPIO11 SCL = A5 = GPIO12 |
Common Mistake 2: Assuming D13 Means GPIO13
It does not.
|
1 2 3 4 5 |
D13 → GPIO48 |
Meanwhile:
|
1 2 3 4 5 |
GPIO13 → A6 |
Common Mistake 3: Assuming A0 Means GPIO0
It does not.
|
1 2 3 4 5 |
A0 → GPIO1 |
Native GPIO0 is used by the board’s RGB LED path and boot-related hardware.
Common Mistake 4: Changing Numbering Mode to Fix One Library
Changing the global IDE pin-numbering mode may make one raw-GPIO library work but break other code that uses bare Nano numbers.
A better fix is normally:
- use symbolic Nano pin constants everywhere you control;
- translate raw GPIO requirements explicitly;
- change numbering mode only when the entire project expects it.
Common Mistake 5: Using Bare Numbers in Shared Code
A line such as:
|
1 2 3 4 |
const int relay = 7; |
does not tell the reader whether:
|
1 2 3 4 5 6 |
7 means Nano D7 or GPIO7 |
Write:
|
1 2 3 4 |
const int relay = D7; |
or, if raw GPIO is deliberately required, comment it clearly.
Quick Mapping Reference
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
D0 → GPIO44 D1 → GPIO43 D2 → GPIO5 D3 → GPIO6 D4 → GPIO7 D5 → GPIO8 D6 → GPIO9 D7 → GPIO10 D8 → GPIO17 D9 → GPIO18 D10 → GPIO21 D11 → GPIO38 D12 → GPIO47 D13 → GPIO48 A0 → GPIO1 A1 → GPIO2 A2 → GPIO3 A3 → GPIO4 A4 → GPIO11 A5 → GPIO12 A6 → GPIO13 A7 → GPIO14 SDA → A4 → GPIO11 SCL → A5 → GPIO12 SS → D10 → GPIO21 MOSI → D11 → GPIO38 MISO → D12 → GPIO47 SCK → D13 → GPIO48 LED_BUILTIN → D13 → GPIO48 LED_RED → GPIO46 LED_GREEN → GPIO0 LED_BLUE → GPIO45 |
Final Recommendation
For almost every Nano ESP32 Arduino sketch:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
leave: Tools → Pin Numbering → By Arduino pin and write: D0-D13 A0-A7 SDA/SCL MOSI/MISO/SCK/SS LED_BUILTIN LED_RED/LED_GREEN/LED_BLUE |
Switch to raw GPIO-number mode only when you are deliberately porting ESP32 code or using software that explicitly requires native GPIO values.
The core lesson is:
|
1 2 3 4 5 6 7 8 9 10 |
Nano label ≠ native ESP32 GPIO number but symbolic Nano pin names = safe in both numbering modes |
Once that distinction is understood, Nano ESP32 pin handling becomes straightforward.
For the full board hardware reference, see our Arduino Nano ESP32 pinout guide. For comparison with the standard Espressif development board, see Nano ESP32 vs ESP32-S3 DevKitC-1.