End-to-end type safety with Remix and Rust - Part 1: Introduction

Introduction to using Remix with a Rust backend using gRPC.

Blog post author avatar.
David Steiner

· 4 min read

A typesafe stack

Rust is renowned for its performance and memory safety, qualities that have rightfully earned it headlines. Yet, what often goes unmentioned is its expressive type system, heavily influenced by functional languages. This system features algebraic data types, pattern matching, and “monadic” error handling, making Rust exceptionally powerful for backend development.

While the appeal of using Rust across the entire stack is undeniable, with frameworks like Yew and Dioxus making strides, the frontend realm is still predominantly ruled by JavaScript frameworks.

Enter Remix, a cutting-edge framework that elegantly bridges the gap between client-side and server-side logic. Remix excels in enabling type sharing, thereby enhancing type safety across the stack. For more intricate systems, Remix can serve as a Backend-for-Frontend (BFF), interfacing with dedicated backend services where the complex business logic resides.

Friction often arises in the communication between these disparate services. gRPC emerges as a vital solution here, providing a robust channel for type-safe service interactions. Through gRPC, the contract between the Remix frontend and the Rust backend is not only agreed upon but rigorously enforced. This not only streamlines the development process but also significantly strengthens the application’s resilience to integration issues.

In this series of articles, we’ll implement a small (and intentionally overengineered!) application that leverages gRPC for type-safe communication between Remix and a Rust backend. Furthermore, we’ll employ sqlx for the persistence layer ensuring compatibility between Rust types and the database schema. This stack guarantees comprehensive type checking from the user interface down to the database layer.

What are we building?

The application we’re developing might seem straightforward—a simple stock trading app. Yet, it’s complex enough to demonstrate the robust systems and outstanding developer experience achievable with the technologies discussed in this post.

A simple trading app

This application will unfold across a series of posts.

We’ll begin by constructing the backend service in Rust, featuring two gRPC services: one for managing stock reference data and another for processing orders. Orders will be recorded as trades, from which overall positions are calculated.

After finalising the gRPC interface, we’ll generate the client library for the API and integrate it into a Remix application. This application will offer a single page for users to view their positions and execute stock buys or sells.

Required tools

In order to build the application, we’ll use a number of tools that should be installed beforehand.

The steps are tested on MacOS, but should work with minimal modifications on any platform.

Initial setup

The final code for each section will be available as branches on GitHub. The initial setup includes a significant amount of boilerplate code, particularly for the frontend, as one might expect. To bypass the more tedious aspects, a skeleton project has been pushed to GitHub under the v0-initial branch.

Clone the project with the v0-initial tag:

Terminal window
git clone -b v0-initial [email protected]:monadera/remix-rust-grpc-example.git

The repository contains two directories, api and webapp.

The api directory

The api directory will contain the code for the Rust service. You should be able to compile and run the project without any errors.

Terminal window
cargo run

You should also be able to bring up the database by running

Terminal window
docker compose up -d db

The Cargo.toml file is pre-configured with some crates we’ll use, but aren’t essential to the conversation. They are rather mainstream crates, but in case you are new to Rust, here is an explanation:

CrateDescription
anyhowerror handling in applications
dotenvyenv from .env files
thiserrorbetter error types
tokioasync runtime
tracingtracing and logging
tracing-subscribercollecting trace data

The webapp directory

The webapp directory contains the Remix app. It has been pre-configured with linting and code formatting. It also contains the necessary packages for the UI, such as tailwind and shadcn.

Ensure the setup is working correctly by installing the dependencies

Terminal window
npm install

and running the Remix app

Terminal window
npm run dev

Conclusion

We are ready to start working on our trading application! The next installment will see the first gRPC service developed using Rust, tonic, and sqlx.

Next post - Part 2: gRPC reference data service

David Steiner

I'm a software engineer and architect focusing on performant cloud-native distributed systems.

About me

Back to Blog