If you’re holding a Raspberry Pi and wondering which programming language you’re “supposed” to use…good news: you’re not locked into one. The Raspberry Pi is a Linux computer (Pi 5/4/3/Zero) and, in the case of the Raspberry Pi Pico, a microcontroller board (RP2040). That means you can choose from many languages depending on what you’re building—automation scripts, full web apps, low-level robotics, data dashboards, or classroom projects.
This guide walks you through the most common languages on Raspberry Pi, why you’d pick each one, and how they fit into real projects. You’ll also see bite-size code snippets and a quick decision flow to help you choose confidently.
TL;DR — Pick by Project Goal
IoT/automation, quick prototypes, AI experiments: Python
Highest performance, real-time control, drivers: C/C++ (and increasingly Rust)
Web servers, REST APIs, dashboards, cloud glue: JavaScript/Node.js (and Go)
Enterprise/long-lived apps with strong tooling: Java (Pi4J, Spring Boot on ARM)
Learning/education & visual coding: Scratch
Tiny microcontroller projects (Raspberry Pi Pico): MicroPython/CircuitPython or C SDK
System scripting, glue code, cron jobs: Bash (with modern libgpiod tools)
The Big Picture: Pi vs. Pico
Raspberry Pi (5/4/3/Zero) runs Linux. You can install and run Python, C/C++, JavaScript/Node.js, Java, Go, Rust, Ruby, PHP, .NET (C#) and more.
Raspberry Pi Pico is not a Linux computer; it’s a microcontroller (RP2040). Typical languages here are C/C++ (official SDK) and MicroPython/CircuitPython. You flash firmware to the chip rather than running a full OS.
Keep this distinction in mind as you pick a stack.
Python — The Friendly Default (and Often the Fastest Path to Working)
Why Python: Raspberry Pi OS ships with Python, the community is massive, and hardware libraries (GPIO, I²C, SPI, UART) are beginner-friendly. For many automation and IoT tasks, Python gets you from idea to working prototype in minutes.
Great for:
GPIO control (LEDs, buttons, relays), small robots
Reading sensors (temperature, motion, distance)
AI/ML demos (TensorFlow Lite, ONNX Runtime)
Quick web dashboards (Flask/FastAPI + Chart.js)
Home automation (MQTT, Home Assistant integrations)
Starter snippet (blink an LED on GPIO 17) with gpiozero:
pip install gpiozero
from gpiozero import LED
from time import sleep
led = LED(17)
while True:
led.on(); sleep(0.5)
led.off(); sleep(0.5)
Pros
Batteries-included standard library, rich third-party ecosystem
Simple syntax; easy to teach, maintain, and share
Covers 80% of hobby/IoT use cases without touching C
Trade-offs
Slower than compiled languages for CPU-intensive or tight real-time loops
Long-running services benefit from structuring with systemd, venv, and logging
C and C++ — Maximum Performance and Control
Why C/C++: When you need deterministic timing, low latency, or direct access to peripherals, C/C++ is still king. This is also where you’ll write device drivers, performance-critical code paths, and robust robotics control.
Great for:
Real-time motor control, high-rate sensor fusion
Writing/porting libraries and daemons
Multimedia acceleration, video pipelines, SIMD jobs
Typical stacks: pigpio (C interface), libgpiod (modern GPIO), POSIX I/O, or talking to hardware over /dev/i2c-, /dev/spidev.
Tiny example (conceptual):
// Compile with: gcc -o blink blink.c -lpigpio -lrt
include
include
int main() {
if (gpioInitialise() < 0) return 1;
int pin = 17;
gpioSetMode(pin, PI_OUTPUT);
for (;;) {
gpioWrite(pin, 1); usleep(500000);
gpioWrite(pin, 0); usleep(500000);
}
gpioTerminate();
return 0;
}
Pros
Speed, determinism, and mature tooling (gdb, valgrind)
Huge existing codebase across embedded/Linux domains
Trade-offs
More lines of code and lower-level debugging
Memory safety and concurrency require discipline (or…see Rust)
JavaScript (Node.js) — Webby by Nature, Great for APIs & Dashboards
Why Node.js: If you think in web apps, sockets, and JSON, Node on a Pi feels natural. It’s perfect for exposing device data over HTTP/WebSocket, serving a dashboard, or piping events to the cloud.
Great for:
REST APIs and realtime dashboards (Express, Socket.IO)
MQTT brokers/clients, cloud integrations (AWS/GCP/Azure)
Lightweight automation services with npm ecosystem
Blink with onoff:
// npm i onoff express
const Gpio = require('onoff').Gpio;
const led = new Gpio(17, 'out');
// Tiny REST API to toggle LED
const express = require('express');
const app = express();
app.post('/led/:state', (req, res) => {
led.writeSync(req.params.state === 'on' ? 1 : 0);
res.json({ ok: true });
});
app.listen(3000, () => console.log('Listening on 3000'));
Pros
Massive ecosystem (npm), async I/O is a natural fit for IoT
Pairs nicely with React/Vue/Svelte front-ends
Trade-offs
Single-threaded event loop needs care under CPU load
Native modules require ARM builds when needed
Java — Industrial-Strength with a Mature IoT Tooling Story
Why Java: For teams that want structured, long-lived services and excellent observability, Java on ARM works well. You can use Spring Boot for web services and Pi4J for GPIO/I²C/SPI.
Great for:
Enterprise IoT gateways, OTA-updateable services
Complex state machines and integrations
Multi-module projects with strong testing suites
GPIO (Pi4J-style) sketch:
// Pseudo-style to show the idea
var pi4j = Pi4J.newAutoContext();
var led = pi4j.dout().create(17);
while (true) {
led.high(); Thread.sleep(500);
led.low(); Thread.sleep(500);
}
Pros
Excellent tooling, profiling, packaging, CI/CD
Strong type system and libraries
Trade-offs
Heavier footprint than Python/Go for tiny tasks
Startup time and memory need tuning for small Pis
Go — Fast, Simple, Deployable as a Single Binary
Why Go: Compiled performance, easy concurrency (goroutines), and static binaries make Go a favorite for resilient device agents, brokers, and network services.
Great for:
Telemetry collectors and MQTT gateways
Concurrency-heavy services (many sockets, sensors)
Command-line tools and daemons
Blink with periph.io (conceptual):
// go get periph.io/x/conn/v3 periph.io/x/host/v3 periph.io/x/host/v3/rpi
package main
import (
"time"
"periph.io/x/host/v3"
"periph.io/x/host/v3/rpi"
)
func main() {
host.Init()
pin := rpi.P1_11 // GPIO17
for {
pin.Out(true); time.Sleep(500 * time.Millisecond)
pin.Out(false); time.Sleep(500 * time.Millisecond)
}
}
Pros
Memory-safe, fast, great cross-compile story
Easy to ship (single binary + systemd service)
Trade-offs
Fewer electronics-specific libs than Python/C, but growing strong
Rust — Performance with Memory Safety
Why Rust: If you want C-class performance with modern safety guarantees, Rust is compelling. On Pi, the rppal crate gives access to GPIO, I²C, SPI, and UART. It’s excellent for reliable, long-running device services.
Great for:
Robust daemons needing low-level access without GC
Concurrency and correctness with fearless refactors
Performance-critical workloads
Blink with rppal:
// Cargo.toml: rppal = "0.16"
use rppal::gpio::Gpio;
use std:🧵:sleep;
use std::time::Duration;
fn main() -> rppal::gpio::Result<()> {
let mut pin = Gpio::new()?.get(17)?.into_output();
loop {
pin.set_high(); sleep(Duration::from_millis(500));
pin.set_low(); sleep(Duration::from_millis(500));
}
}
Pros
Memory safety, expressive types, great perf
Ecosystem for embedded (embedded-hal), Linux (tokio, axum)
Trade-offs
Steeper learning curve; compile times can be longer
Scratch — Visual Coding for Fast Learning
Why Scratch: It’s block-based, kid-friendly, and terrific for workshops. You can control GPIO through extensions or bridge tools and show immediate feedback on physical hardware.
Great for:
Education, clubs, first-time makers
Quick demos without typing syntax
Pros
Minimal barrier to entry
Visual logic helps teach fundamentals
Trade-offs
Not designed for complex or performance-sensitive apps
MicroPython & CircuitPython (Raspberry Pi Pico / RP2040)
Why MicroPython/CircuitPython: On the Pico, you’ll often choose MicroPython/CircuitPython for instant sensor tinkering without toolchains. It’s REPL-friendly and ideal for classroom microcontroller work.
Blink (MicroPython):
from machine import Pin
from time import sleep
led = Pin(25, Pin.OUT) # Onboard LED on many RP2040 boards
while True:
led.toggle()
sleep(0.5)
When to use the C SDK on Pico:
Highest performance, tight real-time timing, or when you need precise control and memory efficiency.
Bash & System Tools — The Underrated Superpower
Sometimes you don’t need a full app—just a shell script and cron.
Examples:
Log sensor data every minute and append to CSV
Call gpioset/gpioget (from libgpiod) for simple pin control
Glue scripts that call Python/Node/Rust services and rotate logs
!/usr/bin/env bash
Quick LED toggle using libgpiod tools
gpioset gpiochip0 17=1
sleep 0.5
gpioset gpiochip0 17=0
Pros
Zero extra runtime, perfect for automation glue
Trade-offs
Not ideal for complex logic or long-running network servers
Other Languages You Can Use
PHP — If you’re turning the Pi into a LAMP stack web server
Ruby — Scripting and lightweight web apps (Sinatra/Rails)
C#/.NET — Modern .NET runs on ARM; good for teams in Microsoft stacks
Swift — Community builds exist; handy for cross-training Apple-centric teams
R/Julia — Data analysis and scientific computing demos
Common Project Stacks That Work Well
Python + MQTT + InfluxDB/Grafana: Sensor network with a slick dashboard
Node.js (Express) + React/Vite: All-JavaScript device UI and control
Go service + NATS/MQTT: Lightweight, resilient message processing
Rust daemon + Python notebooks: Safe, fast device core; easy data analysis
Java (Spring Boot) + Pi4J: Enterprise-grade IoT gateway with strong ops
Getting Set Up (Quick Notes That Save Time)
Virtual environments (Python): python3 -m venv .venv && source .venv/bin/activate && pip install ...
Systemd services: Keep your app alive across reboots; add a unit file in /etc/systemd/system/ and systemctl enable --now yourapp.service
GPIO tooling: Prefer modern libgpiod (gpiodetect, gpioset, gpioget) over legacy sysfs paths
Node on ARM: Use nvm to manage Node versions; rebuild native modules on the Pi
Cross-compile (Go/Rust/C): CI can produce ARM binaries; test on device for hardware access
Security basics: Use a non-root user, keep ports closed by default, and rotate logs
FAQs
Q: Can I use C#/.NET on Raspberry Pi?
A: Yes. Modern .NET runs on ARM. You can build console services, web APIs (ASP.NET Core), and access GPIO via .NET IoT libraries. It’s a solid choice for teams in the Microsoft ecosystem.
Q: Is Python too slow for “real” robotics?
A: For many robots, Python is fine—especially when the heavy lifting is delegated to native libraries (OpenCV, NumPy) or a microcontroller that handles the tight loops. For strict real-time control, move critical paths to C/C++ or Rust and call them from Python.
Q: RPi.GPIO vs. gpiozero vs. pigpio?
A: gpiozero is the friendliest high-level API; pigpio (daemon-based) is great for precise timing and works with multiple languages. RPi.GPIO is low-level and simple but less ergonomic for beginners.
Q: Which language is “fastest”?
A: In raw speed, C/C++ and Rust typically lead, then Go/Java/Node, then Python/Scratch. But “fastest to working prototype” is often Python.
Q: What about Raspberry Pi Pico?
A: Use MicroPython/CircuitPython for easy tinkering or the C SDK for maximum control and performance.
Example Mini-Project: Temperature API in 3 Flavors
Python (FastAPI):
pip install fastapi uvicorn smbus2
from fastapi import FastAPI
from smbus2 import SMBus
app = FastAPI()
I2C_ADDR = 0x48
@app.get("/temp")
def read_temp():
with SMBus(1) as bus:
raw = bus.read_byte(I2C_ADDR) # demo: pretend 1-byte temp
return {"celsius": raw}
Run: uvicorn app:app --host 0.0.0.0 --port 8000
Node.js (Express):
// npm i express i2c-bus
const express = require('express');
const i2c = require('i2c-bus');
const app = express();
app.get('/temp', async (_, res) => {
const bus = await i2c.openPromisified(1);
const raw = await bus.readByte(0x48, 0x00); // device/register: demo only
await bus.close();
res.json({ celsius: raw });
});
app.listen(8000);
Go (net/http):
// go get github.com/d2r2/go-i2c
package main
import (
"encoding/json"
"net/http"
"github.com/d2r2/go-i2c"
)
func main() {
http.HandleFunc("/temp", func(w http.ResponseWriter, r *http.Request) {
i, _ := i2c.NewI2C(0x48, 1); defer i.Close()
// demo: single-byte read
b := []byte{0}
i.ReadBytes(b)
json.NewEncoder(w).Encode(map[string]byte{"celsius": b[0]})
})
http.ListenAndServe(":8000", nil)
}
Pick the flavor that matches your team and deploy style; all three get you a simple HTTP endpoint you can chart in a front-end or ship to the cloud.
Key Takeaways
There’s no single Raspberry Pi language—choose by project constraints (performance, timing, web UI, team skills).
Python wins for approachability and peripherals; C/C++/Rust win for tight timing; Node/Go/Java win for services and scale.
For Raspberry Pi Pico, think MicroPython (speed of learning) or C SDK (speed of execution).
A Simple Plan to Start (Today)
Define the goal: sensor → API → dashboard? robot → motor control?
Pick the language using the decision flow.
Run a blink or sensor read in your language within 30 minutes.
Wrap it in a service (systemd), log it, and secure the port.
Iterate: add cloud, dashboards, and alerts as needed.
If you do that, you’ll be productive on Raspberry Pi—no matter which language you start with.
Top comments (0)