Arduino uses C++. That is the short answer, and it is slightly misleading, because what you write in the Arduino IDE does not look much like the C++ a desktop developer would recognise.
Arduino sketches are C++ with a simplified structure, a large library of helper functions, and a build process that hides the parts beginners find discouraging. The result feels like its own language, which is exactly the point — and it is also why developers eventually hit limits and need to know what is underneath.
This guide explains what the Arduino language really is, what the framework adds and hides, where its abstractions become a problem, and which languages work as alternatives.
What the Arduino Language Actually Is
An Arduino sketch is compiled by avr-gcc or arm-gcc as C++. Before compilation the toolchain performs a few conveniences:
- Adds
#include <Arduino.h>so the core library is available without you asking - Generates function prototypes automatically, so functions can be used before they are declared
- Wraps your
setup()andloop()in a realmain()that calls them - Links the core library that implements
digitalWrite,analogRead,Serialand the rest
Everything valid in C++ is valid in a sketch: classes, templates, references, standard containers where memory allows. You can also drop straight to C, or to direct register access, in the middle of a sketch.
There is no “Arduino language”. There is C++ with the awkward parts pre-arranged.
Why setup() and loop() Instead of main()
Standard C++ starts at main() and ends when it returns. Embedded firmware never ends — it initialises once, then runs forever. Arduino encodes that reality in its structure:
setup()runs once at power-up: configure pins, start Serial, initialise sensors.loop()runs repeatedly and immediately restarts when it finishes.
Behind the scenes, the generated main() calls setup() once, then loop() inside an infinite loop. Beginners get the correct embedded program shape without having to be told why.
What the Abstraction Costs
The convenience is real, and so is the price. These matter once a project grows beyond a prototype.
| Arduino way | What it hides | When it becomes a problem |
|---|---|---|
digitalWrite() | Pin lookup tables and port manipulation | Tens of times slower than direct register writes; matters in tight timing loops |
delay() | A blocking busy-wait | Nothing else can run; the first thing to outgrow in any real product |
analogRead() | ADC configuration and timing | No control over sampling rate, reference, or averaging |
Automatic main() | Startup and initialisation order | Harder to control low-power startup behaviour |
| Core library always linked | Flash and RAM overhead | Tight on very small microcontrollers |
| No RTOS by default | Task scheduling | Concurrency must be hand-rolled with state machines |
The practical milestone for most developers is replacing delay() with timing based on millis(), because a blocking delay makes it impossible to do two things at once. That single change is the usual step from sketch to firmware.
Other Languages for Arduino-Class Hardware
Using Arduino Well, and Knowing When to Leave
millis()-based timing so the loop stays responsive. This is the difference between a demo and something that can do more than one thing.F() for constant strings on AVR parts.That last point is worth keeping: proving the signal exists before committing to hardware is a core step in building an IoT product, and Arduino remains one of the quickest ways to do it.
Frequently Asked Questions
Conclusion
Arduino uses C++, presented in a way that removes the obstacles that stop beginners. That abstraction is a genuine achievement and the reason an enormous number of engineers started here.
It is also a ceiling. Once a project needs precise timing, low power, certified connectivity, or secure updates, the right move is to keep the C++ knowledge and leave the framework behind — usually for a vendor SDK or an RTOS. Prototyping in Arduino first remains a sensible step regardless of where the product ends up.
