Here's something that cloud-first POS vendors don't like to talk about: the internet in a strip mall is unreliable. Cables get cut during construction next door. The ISP has an outage on a Saturday afternoon. The router in the back office that nobody has rebooted in six months finally gives up.
When that happens with a cloud-only POS, your registers stop. Customers are standing in line with carts full of groceries and your cashier is staring at a loading spinner. I've watched this happen at Poco Loco. It's not a theoretical problem — it's a weekly one.
The architecture
REVOLT runs on Electron with a local SQLite database on every terminal. Every transaction, every product lookup, every price check happens against the local database first. The register doesn't need the internet to ring up a sale.
The sync layer runs in the background. When connectivity is available, the terminal pushes completed transactions to the central API and pulls down any updates — new products, price changes, employee schedule updates. When connectivity drops, the terminal keeps working. Transactions queue up locally and sync when the connection comes back.
This isn't a new pattern. Banks figured this out decades ago. But most POS vendors building for small retail today treat offline as an afterthought — a degraded mode where half the features stop working. We treat it as the default.
SQLite as the local store
We chose SQLite for the terminal database for a few reasons. It's embedded — no separate database process to manage. It's fast for the read-heavy workload of a register (product lookups, price checks, tax calculations). It handles concurrent reads well. And it's one of the most battle-tested pieces of software ever written.
The schema on the terminal mirrors the relevant subset of the central PostgreSQL database. Products, prices, tax rules, employee PINs for clock-in — everything the register needs to function independently. A migration system keeps the local schema in sync when we ship updates.
Conflict resolution
The hard part of offline-first is handling conflicts. What if a price changes on the server while a terminal is offline and has already rung up items at the old price? What if two terminals process returns against the same transaction?
Our approach: the terminal is authoritative for its own transactions. Once a sale is completed locally, that's the record. Price changes propagate on next sync but don't retroactively alter completed transactions. For operations that genuinely require central coordination — like voiding a transaction from a different terminal — those wait for connectivity. The system surfaces these clearly to the operator rather than silently failing.
Why Electron
Electron gets a bad rap for being heavy, and that's fair for a note-taking app. But for a POS terminal that needs deep OS integration — USB receipt printers via ESC/POS protocol, barcode scanner input, cash drawer triggers, customer-facing displays — Electron gives us the bridge between web technologies and hardware that we need. The alternative is building native apps per platform, which we don't have the team size for.
The terminal runs on dedicated hardware. It's not competing with 47 browser tabs for memory. In that context, Electron's overhead is a non-issue.
Internet will always be unreliable in small retail environments. We built REVOLT to not care.