← Blog

Fieldnotes: a small Rust web app, and the deployment lesson around it

A Topcoat proof of concept reached Vercel after a compiler mismatch. What it demonstrates, what it does not, and where agents helped.

Nissan Dookeran4 min readRustTopcoatOpenClawWeb Engineering

Fieldnotes failed its first hosted build before it could serve a page. The compiler was too old.

The app and its Topcoat dependencies required Rust 1.99. Vercel had selected 1.92. The fix was three lines in a toolchain file, plus a README change. There was no dependency downgrade or rewrite.

The app is live now. It's a notebook with three synthetic notes and a category filter. Small enough to see what Rust web development looks like without first building an account system or connecting a database.

Why try this with Rust?

Topcoat puts HTML views in Rust. For a team already working in Rust, that's a reason to try a small interface and see how the code reaches the browser.

Fieldnotes uses Topcoat 0.11's view! macro to render the page. A Rust function on Vercel handles the request and returns the HTML. Choose a category and the browser makes another GET request. The selection stays in the URL, so you can share the filtered view by copying the address.

That interaction needs no browser JavaScript. It suits this little notebook: choose a category, get the matching notes. An editor with frequent local updates would ask different questions of the stack.

Topcoat has more to it than this sample uses. Its browser-reactivity system translates supported Rust expressions into JavaScript; Fieldnotes leaves that part alone. The upstream README also calls the framework early-stage and experimental, with breaking changes expected. This is a Labs sample, not a commitment to move the existing Next.js site.

The missing piece was compiler selection

The local release build and tests had passed with the required compiler. HTTP checks exercised the handler: the full page returned three notes, the interaction filter returned one, and unsupported POST requests were rejected.

The hosted build stopped at:

rustc 1.92.0 is not supported

There had also been a deployment access hurdle involving commit authorship. Getting a build authorised resolved that hurdle; it couldn't change which compiler the builder used.

The app already declared its minimum Rust version. That declaration lets Cargo reject an older compiler. It doesn't tell the environment to select a newer one.

The repair added rust-toolchain.toml beside the app:

[toolchain]
channel = "1.99.0"
profile = "minimal"

The README was updated to explain the selection and local validation. The compiler requirement could now travel with the source instead of depending on the builder's default. The rustup documentation explains this mechanism and the command-line or environment overrides that can take precedence.

The repaired production build succeeded. The hosted log didn't print the compiler version, so Rust 1.99 selection is inferred from the pin and the successful build, rather than read from a compiler banner.

There was still a page to check. An earlier deployment URL had returned HTTP 200 for Vercel's "Deployment has failed" screen. After the repair, the public URL returned the actual Fieldnotes notebook, and the category URL returned the matching note. Local handler checks, a successful hosted build and a working public page had each answered a different question.

Where this leaves the experiment

The appeal here is fairly specific. A Rust view, an HTTP handler and a URL hold enough of the application for this interaction. There is no client bundle to coordinate. For a small read-oriented tool, that is worth a look.

The deployment work belongs in that evaluation too. Vercel's Rust runtime is beta, and this attempt needed an explicit compiler selection before it would build. Choosing Rust for the view didn't remove the hosting integration work.

Fieldnotes is too small to support a speed, cost or security comparison with JavaScript or Next.js. It has synthetic content and no persistent writes or authentication. Its useful result is narrower: this particular Rust web app can be built, hosted and opened at a public URL.

For agent-assisted development, the compiler mismatch is a concrete example of why a completion message needs checking against the intended result. A passing local test was useful evidence. The page at the end of the link was what readers needed.