Flash your board
The first time you connect a board, Kog performs a one-time setup: it downloads the prebuilt Kog runtime firmware for your chip and flashes it. After that, deploying your app takes about a second, because only the tiny app bundle moves.
You don't need the CLI to get Kog onto a board. The Run on your board page flashes and hot-reloads a blessed board entirely from Chrome or Edge over Web Serial, with no CLI, Python, or toolchain. This guide covers the CLI path, which you'll want once you're developing locally.
First flash
npm run flash # from a scaffolded project
# or directly:
npx kog flash
What happens:
- Detection: the CLI scans USB serial ports and identifies your board by its USB identifiers and chip handshake. When two blessed boards share a chip, it reads the flash part's size to tell them apart (see Two ESP32-S3 boards). ESP32-S3/C3/C6 boards use native USB and need no drivers on macOS, Windows, or Linux.
- Runtime download: the prebuilt runtime images for your board (a few MB) come from the board-image manifest: the one you pass with
--manifestif any, otherwise a local build inside the Kog repo (native/build-wasm/flash/boards.json) if one exists, otherwise the hosted manifest. - Flash: the bootloader, partition table, OTA data, runtime image, and a development-posture NVS partition (dev mode on, plus any Wi-Fi credentials from your
kog.config) are written in one pass, each part verified against its SHA-256 before it's written. The board's display and pin configuration is compiled into its runtime image. Flashing is implemented in pure Node (no Python, noesptoolinstall). - Wi-Fi handoff (optional): while still connected over USB,
npm run wifihands the device your Wi-Fi credentials so your app can use the network (fetch,WebSocket,WiFi). Code still moves over USB only.
Typical first-flash time: under a minute. After that, npm run dev skips straight to pushing your app bundle (~1 second), and npm run deploy installs a build as the device's standalone app.
USB drivers
Most boards enumerate as a USB serial port the moment you plug them in. Which driver (if any) you need depends on the USB-to-serial bridge on the board:
| Bridge chip | USB vendor ID | Driver | Boards |
|---|---|---|---|
| Espressif native USB | 303a | None (built into the OS) | ESP32-S3 / C3 / C6 (e.g. Waveshare 1.46B, AMOLED-2.06) |
| Silicon Labs CP210x | 10c4 | Usually none on modern OSes; CP210x VCP driver if the port doesn't appear | Many ESP32 dev boards |
| WCH CH340 / CH343 | 1a86 | Usually none on modern OSes; CH34x driver if the port doesn't appear | ESP32-2432S028R "Cheap Yellow Display" |
| FTDI | 0403 | Built in | Older / breakout boards |
Run kog doctor to see the serial ports Kog can find and whether a driver looks missing.
Picking the port
With one board plugged in, kog flash and kog dev auto-select it. If you have several serial devices attached (or the wrong one is chosen), name the port explicitly:
npx kog flash --port /dev/cu.usbserial-210 # macOS
npx kog flash --port COM5 # Windows
npx kog flash --port /dev/ttyUSB0 # Linux
Ports look like /dev/cu.usbserial-* or /dev/cu.usbmodem-* on macOS, COM* on Windows, and /dev/ttyUSB* / /dev/ttyACM* on Linux.
Troubleshooting
| Symptom | Most likely cause | Fix |
|---|---|---|
| No board found / port list empty | driver or cable | Install the driver for your bridge chip (table above); try a different USB cable (some are charge-only) |
| ESP32-S3 board missing from the list | wrong USB port | Use the board's native USB-C port, not a separate UART header |
sync-failed / chip won't respond | auto-reset didn't enter the bootloader | Unplug and replug; some CYD clones need the BOOT button held while connecting |
verify-mismatch on a part | corrupted download or a stale cache | Re-run the flash. The SHA-256 check is working as intended: it refuses to write a bad image |
| Flashes fine but the screen stays blank | app slot empty on first flash | Expected. Push an app with npm run dev (hot reload) or npm run deploy (standalone) |
| CYD screen is left/right mirrored and blue UI renders orange | classic panel generation (same silkscreen, different glass) | Reflash with npx kog flash --board cyd-classic (see below) |
board-ambiguous on an ESP32-S3 board | the flash part's size couldn't be read | Name the board: npx kog flash --board waveshare-amoled-2.06 or --board waveshare-1.46b (see below) |
| ABI mismatch when pushing an app | device runtime is older than your CLI | Re-flash the runtime: npx kog flash. This rewrites the board's NVS settings (dev mode, plus Wi-Fi from your kog.config), so re-run npm run wifi if you provisioned Wi-Fi that way |
Two ESP32-S3 boards
The Waveshare 1.46B and AMOLED-2.06 are the same chip, but they ship different flash parts: 16 MB
on the 1.46B and 32 MB on the AMOLED-2.06. After it syncs with the chip, kog flash reads the
flash part's id and picks the board from its size, so you don't pass --board. The browser
flasher and Studio do the same.
Only if the flash id can't be read (or names a size neither board ships with) does the CLI stop
with board-ambiguous and ask for --board, and the browser flasher show its board picker. If you
pass a --board that contradicts the detected size, the CLI flashes what you asked for, but first
warns and names the board that matches. A 1.46B image on an AMOLED-2.06 writes fine and then
drives a panel that isn't there.
Two kinds of CYD
The ESP32-2432S028R ships in two panel generations with the same silkscreen: standard glass
(cyd) and the older ILI9341-generation glass (cyd-classic: BGR color order and mirrored scan,
typically the micro-USB-only units). You can't tell them apart from the outside or over USB, so
the CLI asks you to pick when it can't tell:
npx kog flash --board cyd # try this first
npx kog flash --board cyd-classic # if the screen came up mirrored with orange-instead-of-blue UI
The two symptoms together identify the panel: on the wrong image the UI is crisp and touch works, but everything is left/right mirrored and colors that should be blue render orange. Trying the other image damages nothing, so flash back and forth freely. The browser flasher offers the same two choices when it detects a plain ESP32.
Flashing from the browser instead? The Run on your board page has its own troubleshooting for Web Serial, and the same driver notes apply.
When the runtime updates
Your app bundle declares the runtime ABI it was built against, and the CLI checks the device before pushing. If they don't match, the CLI refuses the push and tells you to reflash the board's firmware (kog flash). If the board's runtime is the newer one, update the CLI instead (npm i -D kog@latest).
Reflashing rewrites the board's NVS settings partition: dev mode, plus any Wi-Fi credentials from your kog.config. Wi-Fi you provisioned with kog wifi alone has to be provisioned again.
Development vs. production
A board is in one of two postures, and the command you run picks it:
- Development: the posture
kog flash(andkog dev) leave the board in. The runtime reserves a small dev-link channel sokog devcan hot-reload your code over USB in about a second. Hot reload is USB-only. There's no Wi-Fi/network code push; a board's Wi-Fi is for your app's own networking. - Production: the posture
kog deploysets. It installs your app as the board's standalone program (signed when you configure a key; a bundle that fails its trial boot isn't promoted, though the previous app may not be restored, a known issue; see OTA), turns hot reload off, and gives the full RAM to your app. A deployed board has no code-push channel. To develop on that board again, runkog flash.
Kog runs a single JavaScript engine, MQuickJS, so every prebuilt image ships it, the CYD and the Waveshare/ESP32-S3 alike. MQuickJS runs your app's bytecode in place from read-only flash instead of copying it into the JS heap. That is what lets even a PSRAM-less board like the CYD keep a running app and the hot-reload dev-link in RAM at once, with ~95 KB free: enough for networking and the dev-link together. The CYD prebuilt is validated on hardware.
You don't have to think about any of this. kog dev and kog deploy read the connected board's runtime over the live link and confirm your app is compiled for it (kog dev prints a Board linked: … (abi …, bcv 44283) line). A board still on the retired quickjs-ng firmware is detected too — you'll be told to reflash it (kog flash) to the MQuickJS runtime, then retry. Everything else is identical everywhere: the same source, the same @kog/ui, the same workflow.
Which boards work?
- Blessed boards (tested by us, prebuilt images hosted): see Boards. The reference targets are the Waveshare ESP32-S3-Touch-LCD-1.46B and the ESP32-2432S028R "Cheap Yellow Display"; the Waveshare ESP32-S3-Touch-AMOLED-2.06 is the newest.
- Other boards: not supported yet. A generic prebuilt image configured by your
board.yaml(no compiling), andkog firmware buildfor fully custom runtimes, are planned. See Boards & custom hardware.
The CYD (ESP32-2432S028R, cyd) and Waveshare ESP32-S3-Touch-LCD-1.46B prebuilts are validated on real hardware running the MQuickJS engine: flash and hot-reload are confirmed on-glass on both, and the kog deploy OTA arc on the CYD. The Waveshare ESP32-S3-Touch-AMOLED-2.06 (waveshare-amoled-2.06) prebuilt is confirmed on a real board for flash (with flash-size auto-detection), hot reload and kog deploy; touch accuracy across the glass, colors by eye, and the SD slot are not yet checked. The cyd-classic prebuilt was diagnosed from a real classic-panel unit (its display quirks are the only difference from cyd) but is not yet hardware-validated end-to-end; flashing it writes the same SHA-verified images, and you can always return to cyd by reflashing.