Apache-2.0 · ESP32 · ESP32-S3 · ESP32-C3 · ESP32-C6

Change what the board does without reflashing it.

ESPIDFORTH is a Forth interpreter running natively on ESP-IDF — no Arduino layer. Open a serial console and the firmware becomes editable at runtime: define a word, run it, redefine it, roll it back.

============================================
  ESPIDFORTH v0.5.0
  Build: Sep 19 2026 13:02:41
============================================
No PSRAM, using 100 KB Forth heap
Forth engine initialized.

ok> 2 3 + .
5
ok> : square dup * ;
ok> 12 square .
144
ok> : square dup dup * * ;   \ redefine it, live
ok> 12 square .
1728
ok> chip-info
Chip: ESP32-C3 rev 4, 1 core(s)
Features: WiFi BLE
MAC: 12:34:56:78:9a:bc
Free heap: 198432 bytes
ok> 

Quick start

You need PlatformIO. Pick the environment that matches your board; every one of the six builds in CI.

# clone and flash a C3 devkit, then attach the monitor
git clone https://github.com/IoTone/ESPIDFORTH.git
cd ESPIDFORTH
pio run -e esp32c3 -t upload -t monitor

# other targets
pio run -e esp32s3 -t upload -t monitor    # S3, PSRAM, 512 KB dictionary
pio run -e esp32c6 -t upload -t monitor
pio run -e esp32   -t upload -t monitor    # classic Xtensa, UART0 console

# _release variants strip the on-device test suites (~5.5 KB)
pio run -e esp32c3_release -t upload

When the monitor attaches you get an ok> prompt. Type words to list the vocabulary, test to run 58 built-in assertions on the board, chip-info to see what you are sitting on, and bye to leave.

Using it as a component. components/forth/ is a self-contained ESP-IDF component with no dependencies beyond the SDK. Copy it in, give it two character-I/O callbacks, and call forth_init() — the whole public API is fourteen functions in one header.

Why this instead of plain C or MicroPython

All three run on the same silicon. They differ in what a change costs you and what you give up to get it.

ESP-IDF in C MicroPython ESPIDFORTH
Cost of one change Edit, rebuild, flash, reboot — tens of seconds, and you lose all runtime state Paste at the REPL; instant Type at the REPL; instant
Flash footprint Only what you write ~1.5 MB for a standard build† 183 KB dev · 178 KB release
Static RAM Yours to budget Interpreter + GC heap, ~100 KB and up† 67 KB
Redefining live behaviour Not without a reflash Rebind a name; no rollback primitive A dictionary savepoint rolls a bad patch back word-for-word
Timing determinism Fully deterministic Garbage collector can pause you No GC — fixed dictionary and a bump allocator
Reaching an ESP-IDF API Call it Write a C module, rebuild the firmware A five-line C wrapper, registered at boot
Floating point Full Full None. Integer cells only
Library ecosystem The entire vendor SDK Large — drivers for most common parts Essentially none. You write the wrappers
Learning curve C — familiar Python — familiar Postfix and an explicit stack — unfamiliar to most

† ESPIDFORTH figures are measured from this repository at v0.5.0 (esp32c3 and esp32c3_release). MicroPython figures are approximate for a standard ESP32 port and will vary with the build.

The honest version

ESPIDFORTH wins on exactly one axis and it is a narrow one: the cost of changing a running system. If the board is on your bench and you are trying to find out what a sensor actually does, or it is deployed somewhere inconvenient and you need to adjust its behaviour without shipping a firmware image, that axis is the whole game.

If you need floating-point maths, an I²C driver someone else already wrote, or a team that can read the code without learning a new evaluation order, you want MicroPython or C. Those are good answers and this project does not pretend otherwise.

Current engine is a stub. The interpreter in components/forth/ is an original implementation of the core ANS word set written for this project — roughly 90 words. The full ESP32forth v7.0.8.0 engine is vendored in third_party/ and will replace it once its Arduino dependencies are stripped. Everything on this site is written against the stub, which is what ships today.

What people use it for

Bench bring-up

New board, undocumented peripheral. Poke it from the prompt until you understand it, then write the C once you know what you are writing.

Field-patchable behaviour

Ship one firmware image, then send small Forth bundles over the air. forth_eval_rollback() applies a bundle line by line and reverts the whole thing if any line fails.

Manufacturing test fixtures

Per-unit test sequences as text over the serial link, changeable without re-flashing the fixture between product revisions.

Very small nodes

67 KB of RAM and 178 KB of flash leaves room on parts where a Python runtime simply will not fit.

Teaching

The entire language — parser, compiler, interpreter — is one readable C++ file. Students can modify the language itself in an afternoon.

Embedding in a larger firmware

The engine is a component, not an application. Register your own words and drive it from whatever already owns your main loop.

Projects built on it

ESPIDFORTH was extracted from Project MagNET, an IoT data-sync and control platform, and MagNET remains its largest consumer. Most of the engine's API exists because one of these asked for it.

Hive AI — reference-designs/MagNET_M5DialFiddlerCrab

A swarm of small ESP32 nodes under a coordinating "ruler". A node joins the hive, requests a role, and is sent a role bundle — a signed JSON envelope carrying Forth source, typically under 2 KB, that the node installs and runs without reflashing. That is the mechanism tutorial 10 teaches, in production.

MeasureScaleNotes
Reference designs on the engine17Cameras, environment sensors, LED matrices, audio, mmWave presence, e-ink scribes
Registered FFI words170Against ~90 in the stock engine — the wrapper pattern scales
Typical role bundle< 2 KBFits one hive KV_DATA frame

Vocabularies are built per device from the same five-line wrapper shown in tutorial 8 — cam-snap, temp?, ws-px, mr60-status, scribe-store. A bundle written against the capabilities a node advertises runs on any chip family that offers them.

Hanasu — reference-designs/MagNET_Thread_COaP_hanasu_esp32c6

話す — peer-to-peer mesh chat over Thread and CoAP on the ESP32-C6, with no border router and no WAN. Its serial link is dual-mode: a line is either a structured HCP command or raw Forth, dispatched on the fly. That is why forth_set_io() exists — the link owns the input stream and drives the engine line by line with forth_eval() rather than surrendering to the blocking REPL.

Hanasu also shows the engine's portability boundary. It carries the role-bundle component but not the hive-KV words, which were deliberately split out so the bundle engine has no WiFi dependency and ports to Thread. Thirty-one mn-* words cover mesh state, peers, time sync and chat.

A nice piece of Forth reasoning from that project: botmode is a colon definition rather than an FFI primitive, because an FFI word cannot distinguish an empty stack from a pushed 0 — this engine's pop() returns 0 on underflow, so a bare botmode would read as 0 botmode and arm bot 0. depth can see the caller's stack and disambiguate:

: botmode  depth 0> if mn-bot! else mn-bots then ;

What these consumers drove into the API

Learning references

Forth is old, small, and unusually well documented. These are the sources worth your time, starting with the project this one is built from.

The project we forked

ESP32forth / µEforth — Brad Nelson (flagxor)
The Arduino-hosted Forth for ESP32 that ESPIDFORTH exists to port. We vendor it unmodified at revision ffef117 (v7.0.8.0) in third_party/esp32forth/, under Apache-2.0, as the reference for the ongoing port. If you want a mature, feature-complete ESP32 Forth today, use this rather than waiting for us.

Learning the language

Starting Forth — Leo Brodie
The book nearly everyone learns from, free online. Chapters 1–5 cover everything in our tutorials and then some. Written for a 1980s Forth, so ignore the parts about block editors.
Thinking Forth — Leo Brodie
Not about syntax — about how to decompose a problem into small words. It is one of the better books on software design generally, and it is free.
The Forth Standard
Reference for standard word names and stack effects. Useful for checking what a word is supposed to do; note that our stub implements a subset.

The platform underneath

ESP-IDF Programming Guide
Where you look up the API you are about to wrap in a Forth word — GPIO, ADC, I²C, timers, Wi-Fi.
This repository
components/forth/forth_core.h is the API surface and is heavily commented; forth_core.cpp is the whole language. third_party/esp32forth/PROVENANCE.md records the upstream revision and licence handling.