The Core Confusion: IDE Implementation vs. Sketch Language

When embedded systems beginners ask, "what language is arduino ide in", they are almost always conflating two entirely distinct software layers: the Integrated Development Environment (IDE) itself, and the sketch programming language used to write firmware. Understanding this distinction is the first step toward mastering professional microcontroller development.

The short answer is twofold: The modern Arduino IDE (version 2.x) is primarily written in TypeScript, JavaScript, and Go. However, the code you write inside the IDE (your sketches) is compiled as C++. Let us dissect both layers and explore the C++ coding patterns that separate hobbyist scripts from production-grade firmware in 2026.

Under the Hood: What Language is Arduino IDE In?

To understand the toolchain, we must look at the architecture of the modern IDE. The legacy Arduino IDE 1.8.x was built on the Processing Java framework. However, the current Arduino IDE 2.x represents a massive architectural shift designed to support modern language servers, autocomplete, and debugging.

The Frontend: Eclipse Theia (TypeScript/JavaScript)

The graphical user interface of Arduino IDE 2.x is built on Eclipse Theia, an open-source framework for building cloud and desktop IDEs. Theia is written in TypeScript and runs on the Electron framework (which uses Node.js and Chromium). This is why the IDE feels similar to Visual Studio Code; it leverages the same underlying web technologies to render the text editor, file explorer, and serial monitor.

The Backend: arduino-cli (Go)

The actual heavy lifting—compiling code, managing board packages, and flashing firmware—is not done by the TypeScript frontend. Instead, the IDE communicates via gRPC with a backend tool called arduino-cli. As detailed in the Arduino CLI Documentation, this command-line tool is written in Go (Golang). Go was chosen for its exceptional cross-compilation capabilities, fast execution, and single-binary deployment, making it ideal for managing complex GCC toolchains across Windows, macOS, and Linux.

The Sketch Language: C++ with Arduino Wrappers

While the IDE is built with web technologies and Go, the firmware you write in the .ino files is strictly C++. The Arduino core libraries are essentially C++ wrappers around low-level C hardware registers. When you compile a sketch for an ATmega328P (Arduino Uno), the IDE invokes avr-gcc (a C++ compiler). When targeting an ESP32-C6, it invokes riscv32-esp-elf-gcc.

Expert Insight: The Arduino preprocessor automatically converts your .ino file into a standard .cpp file before compilation. It does this by injecting #include <Arduino.h> at the top of your file and auto-generating function prototypes for any custom functions you define. This hides C++ complexity from beginners but often causes cryptic compilation errors if you use advanced C++ templates or namespaces.

C++ Code Patterns & Best Practices for Microcontrollers

Knowing that your sketches are C++ allows you to leverage modern language features while avoiding patterns that cause catastrophic memory failures on resource-constrained microcontrollers. Below are the critical best practices for writing robust Arduino C++.

1. The Dynamic Memory Trap: Banning the String Class

The most common failure mode in Arduino programming is heap fragmentation caused by the String class. On an ATmega328P with only 2,048 bytes of SRAM, dynamically allocating and destroying String objects rapidly fragments the heap, leading to sudden device reboots or locked states.

Memory Footprint & Safety of Common String Patterns (ATmega328P)
Code Pattern SRAM Impact Heap Fragmentation Risk Best Practice Verdict
String s = "Hello" + val; High (Dynamic) Critical / Severe Avoid entirely on 8-bit MCUs
char buf[32]; snprintf(...) Fixed (Stack/Global) Zero Standard for production firmware
const char* PROGMEM Zero SRAM (Uses Flash) Zero Mandatory for static UI/Logs
std::string_view (C++17) Minimal (Pointer+Len) Zero Excellent for ESP32/ARM parsing

Actionable Pattern: Replace all instances of String concatenation with fixed-size character arrays and snprintf. For example, instead of String payload = "{\"temp\":" + String(dht.readTemperature()) + "}";, use:

char payload[32]; snprintf(payload, sizeof(payload), "{\"temp\":%.2f}", dht.readTemperature());

2. Leveraging constexpr Over #define

Legacy Arduino tutorials heavily rely on the C preprocessor directive #define for pin assignments and constants. In modern C++ (supported by all current AVR and ARM GCC toolchains), constexpr is vastly superior. It provides strict type checking, respects scope and namespaces, and is evaluated at compile-time, resulting in zero runtime overhead.

Bad: #define LED_PIN 13
Good: constexpr uint8_t LED_PIN = 13;

3. Flash Optimization with PROGMEM

When storing large lookup tables, JSON templates, or error messages, storing them in SRAM will quickly exhaust your memory budget. The avr-libc User Manual details the PROGMEM attribute, which forces the compiler to store data in the 32KB Flash memory instead of the 2KB SRAM. You must then use specialized functions like pgm_read_byte() or strcpy_P() to read the data at runtime.

The Compilation Pipeline: From .ino to Machine Code

To debug complex linker errors, you must understand the four-step pipeline the Go-based arduino-cli executes when you click "Upload":

  1. Preprocessing: The .ino file is concatenated with any included tabs, #include <Arduino.h> is injected, and function prototypes are generated. The output is a standard .cpp file in a temporary build directory.
  2. Compilation: The GCC toolchain compiles the .cpp file and all linked library source files into individual object files (.o), applying optimization flags (typically -Os for size optimization).
  3. Linking: The linker (avr-ld or equivalent) combines your object files with the Arduino core library objects and the standard C library (libc.a) into a single Executable and Linkable Format (.elf) file. This is where "undefined reference" errors occur.
  4. Object Copy: The avr-objcopy utility extracts the raw binary instructions from the .elf file and formats them into an Intel HEX (.hex) or binary (.bin) file, which is then flashed to the microcontroller via AVRDUDE or esptool.

Advanced Toolchain Integration for 2026

While the Arduino IDE is excellent for prototyping, professional firmware engineers often outgrow its limitations regarding unit testing and CI/CD pipelines. Because the underlying language is standard C++, you can seamlessly transition to advanced build systems.

Tools like PlatformIO (which integrates into VS Code) or pure CMake workflows utilize the exact same GCC compilers and Arduino core libraries but expose the underlying CMakeLists.txt or platformio.ini configuration files. This allows you to integrate GoogleTest for hardware-in-the-loop (HIL) testing, enforce MISRA C++ compliance via static analyzers like Clang-Tidy, and manage complex dependency trees that the Arduino Library Manager struggles to resolve.

Frequently Asked Questions (FAQ)

Can I write pure C code in the Arduino IDE?

Yes. Because C++ is largely a superset of C, you can write standard C code. If you name your files with a .c extension in the IDE's source folder, the GCC toolchain will compile them using the C compiler (avr-gcc) rather than the C++ compiler (avr-g++). However, you will lose access to Arduino-specific C++ classes like Serial or Wire within those specific .c files.

Does the Arduino IDE support Python?

No. The Arduino IDE does not compile or execute Python. Microcontrollers execute compiled machine code (C/C++ or Rust). While frameworks like MicroPython exist for ESP32 and RP2040 boards, they require a completely different IDE and flashing workflow, bypassing the Arduino C++ toolchain entirely.

Why do I get "undefined reference to setup" errors?

This linker error usually occurs when the Arduino preprocessor fails to recognize your file as a valid sketch. Ensure your main file shares the exact same name as the parent folder and has the .ino extension. If you are using external .cpp files, ensure you have manually included #include <Arduino.h> at the top of them, as the preprocessor only injects this into the main .ino file.