DEV Community

Alex Mo
Alex Mo

Posted on

What Programming Language Is Used for Raspberry Pi? (A Practical, No-Nonsense Guide)

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)