In the world of full-stack TypeScript development, achieving end-to-end type safety has become a holy grail. It promises to eliminate a whole class of runtime errors, enhance developer productivity, and provide a seamless development experience. Two solutions that have emerged to tackle this challenge are tRPC and Freestyle. Let’s explore how each approach handles building a simple greeting API, with a focus on creating typesafe APIs.
tRPC: Move Fast and Break Nothing
tRPC has gained significant popularity for its ability to provide end-to-end typesafe APIs without the need for code generation. Its tagline, “Move Fast and Break Nothing,” encapsulates its philosophy of boosting productivity while maintaining robust type safety.
Let’s see how we’d implement a simple greeting API using tRPC:
On the client side, we can use this API with full type safety:
tRPC shines in its simplicity and its ability to provide automatic typesafety without any build or compile steps. It’s framework agnostic and has a light bundle size, making it easy to integrate into existing projects.
Freestyle: The TypeScript Native Cloud
Freestyle takes a different approach to achieving end-to-end type safety. It aims to unify the frontend and backend into a single TypeScript codebase, eliminating the need for a separate API layer altogether.
Freestyle’s philosophy is to leverage the APIs already built into ECMAScript standards, rather than adding new opinionated APIs. This means you can use TypeScript as your database, blob storage, RPC layer, and more.
Let’s implement the same greeting functionality using Freestyle:
On the client side, we can interact with this cloudstate class directly:
Freestyle’s approach allows developers to work with backend logic as if it were local state, providing a seamless and typesafe development experience. No Zod for type validation—just pure TypeScript.
A More Complex Example: Todo List Application
To better illustrate the differences between tRPC and Freestyle, let’s implement a more complex feature: a Todo list application with real-time updates.
Todo List: tRPC Implementation
We’ll first create a file for sharing types between the server and client:
Next, we can implement the Todo list application using tRPC:
On the client side, we need to set up the tRPC client. We’ll want to use another package, React Query, for data fetching and mutation:
Todo List: Freestyle Implementation
Now, let’s see how the same Todo list application can be implemented using Freestyle:
On the client side, we can use these cloudstate classes directly:
Freestyle’s built-in useCloudQuery hook automatically handles real-time updates and invalidation, so zero subscription boilerplate or additional packages like React Query are needed.
Key Differences
After examining both the simple greeting API and the more complex Todo list application, we can summarize the key differences between tRPC and Freestyle:
Code Organization:
tRPC: Separates server-side router definitions from client-side query/mutation hooks.
Freestyle: Unifies backend and frontend code in a single paradigm.
Real-time Updates:
tRPC: Requires manual setup of subscriptions and query invalidation.
Freestyle: Provides built-in real-time updates through the invalidate function.
State Management:
tRPC: Developers need to manage state storage separately (e.g., databases in production).
Freestyle: @cloudstate decorator automatically handles state persistence for class properties.
Type Safety:
tRPC: Uses Zod for input validation and derives types from these schemas.
Freestyle: Relies entirely on TypeScript’s native type system.
Client-Side Usage:
tRPC: Requires explicit client setup and query/mutation handling using an additional package, React Query.
Freestyle: Allows direct method calls on cloudstate instances with automatic real-time updates.
Learning Curve:
tRPC: Builds on familiar React and API concepts but introduces its own patterns and hooks.
Freestyle: Introduces new concepts like cloudstate but offers a more unified mental model.
Lines of Code and Functionality:
Implementation
Backend
Client
Total
tRPC
41
66
107
Freestyle
32
22
54
tRPC: Twice as many lines of code due to explicit subscription setup, query/mutation handling, Zod schema definitions, etc.
It’s worth echoing the words of Rich Harris, creator of Svelte, from his famous blog post on writing less code:
This isn’t just boring plumbing that takes up extra space on the screen, it’s also extra surface area for bugs.
Freestyle: Less code—while including both the RPC layer and persistent storage 🤯.
Conclusion: Choosing the Right Tool for the Job
Both tRPC and Freestyle offer powerful solutions for achieving end-to-end type safety in full-stack TypeScript applications. The choice between them depends on your specific project requirements, team preferences, and development philosophy.
tRPC excels in:
Adding type safety to existing API setups
Projects requiring framework agnosticism
Scenarios where a clear separation of concerns is preferred
Greenfield projects seeking a unified full-stack approach
Rapid prototyping and development
Scenarios where built-in state management and persistence are valuable
Ultimately, both tools represent significant advancements in the TypeScript ecosystem. They push the boundaries of what’s possible in terms of type safety and developer experience, leading to more robust, maintainable, and developer-friendly applications.
As you evaluate these options for your next project, consider factors such as your team’s familiarity with traditional API structures, your need for built-in persistence, and your preference for code organization. Whichever path you choose, embracing end-to-end type safety is a step towards more reliable and efficient full-stack TypeScript development.
Subscribe to the latest product updates, articles, and tutorials from Freestyle, a YC-backed company. Be among the first to build full-stack in just TypeScript.