Skip to content
Technology07-Oct-20265 min read

Why our warehouse app runs on Tauri, and when a business app should not.

Most business desktop tools do not need Rust. The Lucky Traders Stock app did: one codebase for Windows and Android, a barcode gun heard while Tally has focus, and signed self-updates. Here is the test we use to decide, and what the choice actually costs.

By Mohammad Jamnagarwala · Simply Five Studio

Most desktop tools a business needs do not need Rust. They walk a folder, read a spreadsheet, generate a PDF, call an API, write to a database. A web front end in a plain native window, backed by Python, does all of that well, builds in seconds and ships without ceremony.

So when we built the Lucky Traders Stock app on Tauri, a framework that wraps a web front end in a Rust shell, it was not out of habit. It was because this particular app had needs a simpler wrapper could not meet. The reasoning generalises, and so do the costs.

What did this app need?

The Stock app runs a fastener godown. Pickers receive deliveries, print a QR sticker for every bag and scan bags out as orders are packed. The owner checks figures from wherever they are. Four requirements decided the stack.

It had to run on Android and Windows from one codebase

Receiving happens at the rack, on a handset. Dispatch and purchasing happen in the office, on a Windows machine. Two apps meant two codebases, two sets of bugs and two release cycles for a team that needed one system. Tauri 2 builds a signed Windows installer and an Android APK from the same source, and the screens are the same React code on both.

Most desktop wrappers stop at the desktop. That alone narrowed the field.

It had to hear the barcode gun while Tally had focus

This is the requirement nobody writes in a brief, and it decided more than any other.

A USB barcode gun behaves like a keyboard. It types the code into whichever window has focus. In the Lucky Traders office, the window with focus is usually Tally. A wedge scanner aimed at a bag while Tally is in front sends the barcode into Tally, which is at best useless and at worst an entry in the books.

The answer is Windows Raw Input, which lets an application register to receive keystrokes from a device even when its window is not in front, and tells it which keyboard each keystroke came from. That is an operating system API, and Rust reaches it directly. The app tells a gun from a person by speed: a gun sends a character every few milliseconds, and nobody types that fast. Scans reach the Stock app. Typing stays where the person is typing.

For guns configured as serial devices, the same Rust layer reads the COM port directly.

It had to update itself, safely

A fix is only useful once it is on every machine. Tauri's updater replaces the desktop app in place and refuses any bundle that is not signed with the release key. Android cannot replace itself, so the app downloads the new APK and hands it to the system installer, which checks it against the installed app's signature. Either way, nobody has to visit the godown with a USB stick.

It had to keep a secret properly

The app authenticates with a device token. On Windows that token lives in Credential Manager, not in browser storage where any script in the page could read it. Network requests go out from Rust rather than from the web view, which also means the server needs no cross-origin exceptions at all.

What it cost

The choice was not free, and it is worth being exact about the bill.

Build times. A Rust release build is slow, and some configuration changes invalidate much of the build cache. A small change can mean a long wait.

Signing keys that cannot be lost. The desktop updater trusts one key. Lose it and no installed copy can ever be updated again; every machine needs a manual reinstall. The Android keystore has the same property. Both belong somewhere other than the machine that builds with them, and deserve the seriousness that implies.

Silent failure modes. Two configuration mistakes let a release build succeed while producing no update signatures, and a release without them is offered to every desktop and then refused by all of them. Neither error announces itself. The only defence is a checklist that looks for the signature files after every build.

Android's own quirks. Printing from an Android web view is defined and does nothing, so stickers print through Android's own print framework via a small native plugin. The Android build itself runs in a dedicated container on our build server, because the toolchain is heavy and particular about where it lives.

None of these is a reason to avoid Tauri. All of them are reasons to choose it only when the app needs what it gives.

The test we use

Before reaching for a Rust shell, we ask four questions.

  1. Does it need to run on a phone or tablet as well as a desktop? If so, a desktop-only wrapper is out.
  2. Does it need operating system reach a web page cannot have? Input from a background window, a serial port, a native print path, the system credential store.
  3. Does it need to ship as a single self-contained executable onto machines where installing a runtime is not an option?
  4. Does it do heavy computation where native speed changes what the user experiences?

If every answer is no, the parsimonious choice wins: a web front end in a plain native window, with Python behind it, built in seconds. Disk space is cheap. Waiting on a release build is not.

If any answer is yes, Rust earns its place. For the Stock app, two of the four were yes, and the barcode gun behind Tally would have settled it alone.

The front end was the same HTML, CSS and TypeScript either way. The choice of shell is a choice about what the app must reach beyond the screen. If you are weighing that choice for a tool your team will live in every day, start a conversation and bring your list of what it must reach.

More reading

Related essays.

Technology

When two databases hold the same customer, you have two truths.

A storefront on one database and an ERP on another is the most common architecture in Indian distribution. It also quietly accrues a debt: every record that lives in both places has to be kept in agreement, and the sync that does it is the part most likely to fail.

Continue the conversation

If this resonated, tell us about your operation.

The contact form takes about two minutes. The reply comes from the founder within two working days.