If you can write index.php, you can already program a microcontroller. That's not a metaphor.
PHP on ESP32 just hit 1.0.0 — the first official release. It takes the real PHP interpreter, the unmodified Zend engine straight from php.net, cross-compiles it for a chip that costs about $4, and runs your PHP on the bare board. No operating system underneath. No transpiler. No "PHP-like" language subset. The same index.php, the same opcodes, the same array_map and preg_match and json_encode — because it is literally the same C code, built for the chip's own CPU.
Hand the same script to this engine or to a desktop php and you get the same output.
Wait — real PHP? On a microcontroller?
Yes. The whole engine is compiled in: the lexer, the parser, the opcode compiler, the VM and executor, the garbage collector, the object/class/exception model. <?php echo 1 + 1; travels the exact same path here as on a server — source → tokens → AST → opcodes → execution.
It runs as native code, not under emulation. PHP's C is built with the chip's own cross-compiler (riscv32-esp-elf for the ESP32-P4, xtensa-esp32s3-elf for the ESP32-S3), and the opcodes execute on the board's CPU. The integration point is the official embed SAPI — the same interface any C program uses to host PHP.
The standard library comes with it: ext/standard, PCRE, JSON, hashing, SPL, reflection, the CSPRNG. Optional extensions layer on per project.
Captured on an ESP32-S3-Zero "Super Mini" (Quad 2MB PSRAM @ 80MHz, CPU 160MHz), PHP 8.4.25, no
opcache, with the native_gpio C extension compiled in. See README.md for the S3 / P4 comparison.
... (boot log) ...
I (562) esp_psram: Found 2MB PSRAM device
I (562) esp_psram: Speed: 80MHz
I (802) cpu_start: cpu freq: 160000000 Hz
I (805) esp_psram: Adding pool of 2048K of PSRAM memory to heap allocator
...
==== php-baremetal benchmark ====
PHP 8.4.25
(PSRAM size/speed and CPU freq are in the boot log above)
PSRAM: 744.7 KB free of 2,048.0 KB | internal RAM: 183.4 KB free of 326.4 KB
compiled footprint (PSRAM consumed to compile a source file):
file lines source compiled
bench_small.php 17 0.4 KB 2.3 KB
bench_medium.php 76 2.0 KB 10.3 KB
bench_large.php 167 4.2 KB 22.4 KB
GPIO tight loop (100000 writes on GPIO 2):
PHP loop: 3229 ns/write -> 309,687 writes/s ~154,843 Hz (empty loop 829 ns)
native C: 357 ns/write -> 2,804,239 writes/s ~1,402,119 Hz (9x faster than PHP)
execution: 1,090-row working set = 403.1 KB in PSRAM (710.1 KB was free)
==== done ====
Here's the "hello world" of embedded — blinking an LED — written entirely in PHP. setup() runs once, then loop($tick) is called forever (Arduino-style; the loop lives in C so the watchdog stays happy):
<?php
// index.php: blink an LED on GPIO2.
define('LED', 2);
function setup(): void {
gpio_mode(LED, GPIO_OUTPUT);
echo 'PHP ' . PHP_VERSION . " up\n";
}
function loop(int $tick): void {
gpio_write(LED, $tick % 2); // on for odd ticks, off for even
delay(500); // milliseconds
}
gpio_mode, gpio_write, gpio_read and delay come from a small built-in extension. echo goes to the serial console. That's it — three lines of PHP driving a physical pin.
Your framework, browsable, on the chip
On a board with networking, the firmware can run an HTTP server and hand each request to a fresh PHP run — the way a script runs behind Apache or PHP-FPM. $_SERVER, $_GET, $_POST, cookies and sessions are populated per request. Whatever your script prints becomes the response body.
That's enough to make a framework browsable: on the ESP32-P4 (32 MB PSRAM), stock Laravel and Symfony both serve pages this way. Not a fork, not a cut-down build — the real thing.
And because every ESP32-S3 has WiFi on the die, a board can create its own network and serve a page over it — no router, no cable. One of the examples, wifi-ap-s3-rgb-manage, boots a WiFi access point and serves a live PHP page that controls the board's onboard RGB LED from your phone.
Here's what happens end to end, and every piece of it is PHP. A one-time init script runs once at boot, before the server starts: it brings up a WiFi access point — SSID, password, 192.168.4.1 — and initializes the onboard RGB LED. Then the HTTP server takes over, and every request runs index.php fresh: it reads the color from $_GET/$_POST, drives the RGB LED (HSV), and prints the page back. So you connect your phone to the board's own WiFi, open the IP, move a slider — and the physical LED on the chip changes color. No cloud, no MQTT broker, no companion app: the microcontroller is the web server, and the whole thing — network, page, and pin — is a couple of .php files.
What actually runs on it
The standard library is always on. Everything else is opt-in per project:
- Language. Classes, closures, generators, exceptions, traits, namespaces, typed properties, enums, attributes — all present, because they are the engine.
-
Text & data.
ctype,mbstring(optional oniguruma),filter,tokenizer, and PDO SQLite for an on-card or in-memory database. -
State.
sessionon the web-server model; a reboot-persistent key-value store (store_*, backed by the chip's NVS) for values that survive a reset; and a volatile in-RAM twin (mem_*). -
Config. A project
.envis baked into the firmware and read as$_ENV/getenv(). - OPcache. The bundled Zend OPcache is ported (no JIT, static) — caches bytecode to the card or into PSRAM so a request stops recompiling the framework every time.
-
TLS. The
opensslextension has two builds — a compact mbedTLS-backed one, and full OpenSSL 3.0 (RSA, EC, X.509) — driving an HTTPS client on a networked board.
The hardware
Two things decide whether a chip qualifies: external PSRAM (the runtime heap is measured in megabytes) and ≥ 8 MB flash (the firmware image is ~3 MB). Core architecture doesn't matter — the portable VM builds on both Xtensa and RISC-V.
| Family | Core | PSRAM | Networking |
|---|---|---|---|
| ESP32-P4 | dual-core RISC-V, up to 400 MHz | up to 32 MB | Ethernet (P4-ETH), WiFi 6 via on-board C6 companion (P4-WiFi-C6) |
| ESP32-S3 | dual-core Xtensa LX7, 240 MHz | 8 MB | Ethernet (S3-ETH), WiFi on every S3 |
PHP 8.3.33, 8.4.25 and 8.5.10 all build today, selectable per project.
And the price tag is the fun part: an entry ESP32-S3 board with PSRAM runs the whole thing for around $4. A full PHP interpreter, on a chip that costs less than your coffee.
Try it in five commands
The supported path is phpflash, a single-binary CLI that scaffolds a project, drives the build, flashes the board and opens the serial console:
phpflash system-setup # once: installs ESP-IDF + the firmware sources
phpflash init my-project # scaffold (asks for board, storage, extensions)
cd my-project
$EDITOR project-src/index.php # write your PHP
phpflash flash # build + flash the connected board
Change the script, reset, and the board runs the new one. That's the whole loop.
So… are you an embedded developer now?
If you've shipped a PHP app, you already know the language, the standard library, the mental model. 1.0.0 means that skill set now reaches down to the metal — a real interpreter, running your real code, on a chip you can hold in your hand. Real PHP, bare metal, about four bucks.
It began as a holiday side-project. It's now a stable, documented 1.0.0 with a public roadmap — and new contributors are very welcome.
An honest word on where it stands
1.0.0 is a milestone, not a finish line. Right now this is firmly for hobbyists and tinkerers — it's a genuinely fun way to reuse your PHP skills on hardware, but it is not (yet) something I'd put in production. A lot is still missing or rough: proper multi-core handling, an I²C bus with real sensor/display drivers, an event-driven execution model, and plenty more.
The good news: that's exactly what 2.0.0 is about, and it's already in progress — dual-core done right, the I²C stack, event-driven mode, touch and IMU boards. If any of that sounds like your kind of thing, the roadmap is public and the door is open.
Links
- 🧠 How it works / deep dive: Real PHP on the ESP32
- 🔬 The full example in detail: php-baremetal.com/blog/php-wifi-web-server-esp32-s3-control-led
- 📦 Firmware repo: github.com/php-baremetal/php-esp32
- 🛠️ The phpflash CLI: github.com/php-baremetal/flash-tool
- 🌐 Project site: php-baremetal.com
If real PHP running bare-metal on a microcontroller made you raise an eyebrow, a ⭐ on the repo helps more people find it. What would you build with it?

Top comments (0)