Remix vs Astro for SaaS
Comparing Remix to Astro for building SaaS applications, with key reasons to choose Remix for your next project.
NPM package downloads
Last week's download comparison for Astro and Remix
Application-first architecture
Remix was built with web applications in mind from day one, which comes with a focus on data fetching, mutationg and revalidating (exactly what SaaS applications need). Astro excels at building content-heavy websites with its "Islands Architecture," which become a limitation for SaaS applications.
A typical SaaS app will generally involve lots of reading and writing of data and you'll eventually need things like complex multi-step forms, real-time data updates and frequent client-side updates - all of which Remix excels at.
Astro's partial hydration approach, while amazing for blogs and marketing sites, can actually work against you in a SaaS context where most of your components need to be interactive anyway.
Real-time data management
SaaS apps often require real-time data updates and Remix's provides a built-in way of handling this using its loader and action system. With this, you get automatic revalidation of data when forms are submitted, optimistic UI updates when mutations are in progress, and nested routing with data loading.
Astro, being primarily focused on static site generation, requires additional setup and external libraries to achieve similar functionality.
Consider the following comparison between how to do optimistic updates in Remix vs Astro.
// Remix - optimistic UI with built-in support export default function TaskList() { const { tasks } = useLoaderData<typeof loader>(); const fetcher = useFetcher(); // Optimistically show the new task state const optimisticTasks = tasks.map(task => { if (task.id === fetcher.formData?.get('id')) { return { ...task, completed: true }; } return task; }); return ( <ul> {optimisticTasks.map(task => ( <li key={task.id}> <fetcher.Form method="post"> <input type="hidden" name="id" value={task.id} /> <button name="intent" value="complete" className={task.completed ? 'completed' : ''} > {task.title} </button> </fetcher.Form> </li> ))} </ul> ); }
// Astro implementation --- // src/pages/tasks.astro import TaskList from '../components/TaskList'; import { getTasks } from '../lib/tasks'; const tasks = await getTasks(); // Handle form submission if (Astro.request.method === 'POST') { const formData = await Astro.request.formData(); const taskId = formData.get('id'); await completeTask(taskId); return Astro.redirect('/tasks'); } --- <ul> {tasks.map(task => ( <li> <form method="post"> <input type="hidden" name="id" value={task.id} /> <button type="submit" class:list={[task.completed && 'completed']} > {task.title} </button> </form> </li> ))} </ul> <!-- Need client-side JS for optimistic updates --> <script> // Handle form submissions document.querySelectorAll('form').forEach(form => { form.addEventListener('submit', (e) => { e.preventDefault(); // Find the button and add completed class immediately const button = e.currentTarget.querySelector('button'); button.classList.add('completed'); button.disabled = true; // Submit the form fetch(form.action, { method: 'POST', body: new FormData(form) }).catch(() => { // Revert optimistic update on error button.classList.remove('completed'); button.disabled = false; }); }); }); </script>
Development velocity
Development velocity matters enormously when working on a SaaS app and Remix has several advantages here. Other than the previously mentioned form handling and data fetching, Remix also helps by not having to context switch between static and dynamic content, has built-in error boundaries and TypeScript support for type-safety across your app.
Performance considerations
Astro is famous fo its "zero Javascript by default" approach but for SaaS you often need to have some level of interactivity to provide the UX people expect in 2024.
Remix does return a JavaScript in responses but it comes with a lot of optimizations out of the box. It uses Vite for bundling and code-splitting, provides parallel data loading via nested routes, predictable caching via HTTP headers and smart revalidation, all of which keep returned response sizes to a minimum.
Launchway is a starter kit for Remix that helps you get started with building your SaaS app. It comes out of the box with authentication, payments, database connection, email handling and more so you can focus on building your app, not the boilerplate code. If you're interested, check out one of the demo apps.