Remix Architecture Patterns


Remix provides amazing flexibility and can be deployed anywhere where JavaScript is running. But how does Remix fit into the bigger application landscape of an organization? Remix provides great utility, but how to best take advantage of it? What things should be handled inside of Remix, and what things are better off done elsewhere? Should we use the express adapter to add a WebSocket server or should that be a standalone microservice? How will enterprise organizations integrate Remix into their current stacks? Let’s talk architecture patterns! In this talk, I want to share my thoughts about how to best integrate Remix into a greater (enterprise) stack.



Hey everyone, what is a software architecture again? A software architecture is the blueprint for your application. You design an architecture to fulfill your requirements and fit to your use case and solve the problem you're having. And then you pick a tech stack to implement the architecture that you just signed. It turns out that react is now also an architecture. This is a really cool take by Dan Abramov, who was recently on Twitter reflecting about the state of react. He states that react is no longer just a library, but also an architecture that can be implemented by different meta frameworks. Really cool take, and I'm excited where this leads. And today I want to talk about remix architecture patterns. That is, commonly used and implemented architectures with remix. And my name is André, I'm a developer from Germany. I work at LinkedIn and currently live in Cupertino, California. In my free time, every Monday, I tutor aspiring developers in Meetup. And in general, I love building for the web. Before I moved to the United States, I wrote my master's thesis about api management patterns. I conducted interviews and talked to software engineers and architects from different companies, and then identified patterns and how these companies managed their APIs. I then documented the results in a coherent and organized way. For that, I created a pattern language. And creating that pattern language was a lot of fun to me, and I learned a lot. So I wanted to do it again, this time for remix. I want to answer the question, how is remix used? So for this, I created a survey that I called the state of remix, and I got 74 replies. Let's keep in mind that 74 replies is not enough to be statistically relevant, but it's certainly enough to analyze or identify common usage patterns. That said, I still want to showcase some of the numbers that I got out from the survey, just because they surprised me so much. The first one here is that over 50% of the participants stated that they use remix professionally. This blew my mind, considering that remix version 1 has only been released a year ago. But it's really great to see that such a big part of the community already makes money with remix. Of those who use remix professionally right now, 50% stated that they migrated from react Router to remix. I thought this number would be way higher, considering the clear migration path between react Router and remix, and also obviously the connection between the two technologies. But it turns out folks really move from all different kind of technologies to remix. react single page applications was still the biggest source or region where people move from. RxJS was mentioned a lot too, ExpressJS, RxJS, Rails, vue. But in general, there are just so many different technologies to build for the web. And folks really stated they move from all different kinds of backgrounds and technologies to remix. And I think this is really cool to see. But let's talk about architecture patterns. Before remix or in general, we can all agree this is a big part of the industry standard right now. You have the single page application architecture. We have an SPA running on the browser on the front end, and you have a standalone api server that then communicates with the SPA. So this is the industry standard right now. How does remix compare to that? When you use MPX-grade remix to bootstrap on your remix application and you just pick the basics, you end up with this. And this is a server environment, right? remix is a HTTP handler that runs on top of a server environment. And if you bootstrap a remix application, it comes with a server environment, which is already kind of scaffolded for you. And on that server environment, you have a web server on which the HTTP handler runs. That was a mouthful. And that kind of creates this PASPA application. And PASPA is this term that stands for Progressive Enhanced Single Page Application, coined by Kenzie Dotz to kind of promote that the application that is created by remix does so much more than an SPA. It even works without javascript. It uses the platform, embraces the platform, emulates the browser's default behavior with javascript if javascript is enabled, and does so many more things for you. So this is why we all love remix. But if you compare it to the SPA architecture, we see that the database layer is still missing. And here, remix is agnostic, so we have to just pick a database ourself, or we choose one of remix stacks, and it will come for free for us. But obviously, this is also optional. You don't always need a database layer. You can also have a CMS instead. But then, either way, what we have here is our first architecture pattern. This is where we all get started with remix. And it's a system architecture that we can use to create for the web. The question then arises is, how do we get from this single page application, industry standard architecture to our remix app? And the answer is, what a lot of folks say they do is, they create this temporary architecture to then move to remix. So they move the react code from the SPA inside remix, but keep the api, the standalone api server around. And then they pass requests from the SPA to that legacy api, forwarding the request through the remix HTTP handler. What's really cool about this architecture and this approach is that you now can refactor your SPA code step by step to take more advantage of the features that remix provides. So you refactor your use query or your use effects with the fetch calls to forms and use fetcher in remix and really make your application progressively enhancing based on the capabilities that remix provides. And at the same time, you move more and more code from the legacy api server into the remix HTTP handler. So you really can do this in vertical feature slices and step by step take more and more advantage of remix capabilities. And this is obviously also an architecture pattern, even if it's hopefully a temporary one because at the end of the day, you want to really sunset that standalone api server and move everything into remix, have full control of the web server and end up with that standalone remix app that we talked about earlier. But it's super generic, right? We just say database and server environment. So we have to be more specific here really to make this more productive. And if you talk about different variations in a pattern language, you talk about variants. And variants are actually all the same thing, just with different characteristics. You are allowed to have a favorite variant also. But here I just want to talk about the most common ones based on the survey data. And the first variant that was mentioned the most is the standalone node one. So you use the ExpressJS adapter, the remix app server or any other deploy target that is node.js based. And now you have this standalone node.js app server, your remix app now running on node.js. And what's really cool about this variant is that it feels very familiar. If you use ExpressJS before or any other node.js based web server or like standalone api server, you can kind of like, it's the same thing. Now you only have remix running on top of there as well. It's also super flexible because you're not tied to a specific hosting provider or service. You can deploy this anywhere where node.js can be deployed. And it's very compatible with all the npm packages and the code you've wrote in the past. So it's a really cool variant. An alternative variant is the standalone Edge one. And this one is obviously very cutting edge because we deploy now to an Edge environment. And I really believe that is a trend, Edge deploy, that remix really helped accelerate. I feel like it all started with remix. remix was pushing, like allowing, having adapters for cloudflare workers and pages, which were also the adapters most mentioned in the survey. And I feel like it all started from there. And now we have so many different Edge environments to choose from, right? We have Dino deploy, we have FlyIO, which creates this like regional distributed long-running servers, which is an Edge-like experience. Vercel and Netlify all both added their own Edge environments. So it's really cool to see that we have all those different adapters now for remix to deploy to the Edge. But what we get from all of them is this like geographic proximity to our users. By deploying to the Edge, we distribute our application across the globe to different Edge environments, different Edge servers. And what's really cool about this also is that a lot of those Edge environments actually are serverless. So we get the same kind of scalability that serverless provides us. And even if the environments are not serverless, they mostly do the same kind of trick. So we create this like very scalable application. So really cool pattern. But what we have to keep in mind here with this variant is that, and that's why I also highlighted the database layer, that if we deploy to different regions, we also have to do that with our database. Otherwise, we won't get as much out of the geographic proximity. We want to get down the response times, but if our database is like super far away from our web app, we don't get as much out of it. So we also have to regional distribute our database. Just something to keep in mind, but still an amazing pattern variant nonetheless. And variant number three is probably my favorite one, and it's called this application cache. So this one is server environment agnostic. It doesn't matter which server environment you pick. This pattern will always work. You just add a Redis or any other in-memory application cache to get rid of some bottlenecks. So the goal here is if your application grows in complexity and you have to fetch a lot of data on every request to kind of mitigate some of like the penalties regarding response time from fetching from the database so much by adding a cache. And this is not really a remix specific issue, right? Like when your application becomes more complicated, you have to counteract that, but it's really easy to do this with remix. Just like for instance, I personally always fetch from my root a lot of data, like the user settings and the user object and the preferred next video to watch, and then the promoted purchases and whatnot. And then having that all live in a cache so that you don't have to fetch it on every mutation is a great way to mitigate the bottlenecks that can come from fetching from the database too often. So definitely a cool pattern. But let's talk enterprise. When I say enterprise, I just mean it becomes even more complicated, right? We already said our application can become more complex. We have to add something like Redis, right? To counteract that. But what if it becomes more and more complicated, right? This is basically enterprise. It's like the end boss in complexity, and when we look back to the industry standard right now, we have this SPA architecture. So enterprise, it just means you have to embed your SPA in an even more complicated or complex environment, but a lot of different teams work together to create one system architecture. So you might have to fetch from a lot of different APIs that all provide different entities for your application, different business logic for your application. And then you have to manage all that loading states and error states and authorization and retries and revalidation, optimistic UIs, all of that for those different APIs that are all probably working a little different inside the front end, inside your SPA. And that can become super complicated and a mess. That's why a lot of folks resort to implementing the back-end for front-end pattern. So that is part of the industry standard as well. It's like this very commonly known pattern where you create this middleware service that is tied to your front end and kind of abstracts away some of the complexity of the system. And you can move a lot of that fetching logic inside this orchestration layer. So now your SPA is protected from fetching from different APIs, and you do that in your back-end that is for your front-end. And this is also a really cool use case for graphql, because if you add graphql on the server, this is where it really shines, orchestrating requests to different servers, aggregating data and then making it accessible. Obviously, you can also add graphql here to the SPA, and then you have to fetch only from one endpoint. But this is a great use case for graphql nonetheless. So the question now is, we know this is the industry standard or part of the industry standard right now. How do we translate this to remix? And it turns out, and I never thought about it this way, and I think it's so cool, is that remix naturally implements the back-end for front-end pattern. A lot of folks in the survey stated that they specifically use remix to implement a back-end for front-end architecture. And it turns out the remix documentation actually has content about this explaining how exactly remix works as a back-end for your front-end. But I never saw this, and I never thought about it this way. And I think it's just so cool that if you use remix, you get full control of your web server and your web server replaces the need for any standalone orchestrations mid-slash middleware layer that you would have needed otherwise. So when you use remix to implement your SPA, you get the back-end for front-end pattern out of the box naturally provided by remix. I think this is just really cool to think about it this way. And obviously this is an architecture pattern that we can use in an enterprise context. And we can even add graphql on top if we need it, right? This is where graphql shines to aggregate and orchestrate data from different endpoints. And that then would translate to a variant of that background for front-end pattern in remix. Sweet. So we have three different pattern candidates that we identified that hopefully temporary pass through to legacy api that kind of acts as a migration step. And then we have to stand alone remix app. This is where we all get started. And then if it becomes more complicated, we out of the box get this back-end for front-end architecture pattern implemented out of the box by remix. And this then creates those three different patterns that you identified. And we saw that there are a lot of different variants and there are so many more variants that I don't even mention. I didn't really talk about FlyIO, Netlify, Ressell, those cool hosting providers that provide so many other interesting things for us. But it really shows how flexible remix is in general. We can deploy to long-running servers, to serverless environments, and to the edge. And we can easily add something like Redis to our application to mitigate bottlenecks and really vary our architecture based on our use case and really align remix with what we want to build, which is really cool to see that remix is so flexible. At the end, now I just want to talk about real-time patterns. So far, we talked about general architecture patterns, and now I want to double-click into real-time. This is ongoing discussion between static experiences and very dynamic experiences and which framework is better suited to develop which kind of application. We call it document web versus web app web. And then we ask ourselves which framework is really suited to create those highly dynamic experiences that we want to create in 2022. And sometimes Figma or Google Docs are used as examples for this highly dynamic experiences we want to create. So which framework would you choose to create something like Figma? In my opinion, I think the scale isn't long enough. The spectrum between static and dynamic, we need to add more to the right of dynamic because what makes Figma and Google Docs highly dynamic are really its real-time capabilities. These are like full stack reactive applications and shout out to that do a lot of cool work in that area. There's actually a lot of startups that try to do something in this area. But from a framework perspective, I believe that none of the frameworks, the web frameworks that we have right now on the react ecosystem provides primitives or conventions to implement real-time capabilities. So when we talk about something like Figma or Google Docs, this is nothing your framework really helps you with. You just have to build those things on top of what the framework provides. That said, that is not really a fault of those frameworks either, because there's just so many open questions on an infrastructure layer or like level, right? Like just to give you one example, serverless functions, like intuitively don't really support something like streaming, like long living responses or WebSocket servers, because they want to shut down after they handled the request. So then aws provides its own solution for how to make WebSockets work with serverless, right? Like connection pooling and stuff like that. So it's just very specific for each infrastructure provider. So how it would be really hard to abstract that and create like a common api on a framework layer. So a lot of construction still going on and open questions, but there's still ways right now, obviously to create real-time capabilities in your react apps. And I just want to showcase three different patterns on how to implement like collaborative features in remix. In the first one I call standalone WebSocket server, it's probably the most straightforward one. You just create a standalone server with a WebSocket server on top of it, and you can now deploy it wherever WebSockets are supported, like a long running node.js server, for instance, and you have it separated from your remix app. What's great about this is that you stay flexible on where to deploy your remix app. Even if you deploy to the environments like Netlify, Vercel, which don't really support WebSockets right now, since your WebSocket server is independent, you can still deploy your remix app there. And then you have to have this like your client side application of your remix application has to communicate with the WebSocket server, and you have to kind of remove some of the logic that you were previously handling in remix with WebSockets now. But it works and it's a great way to add real time capabilities. Even cooler, I think, depending on use case, is to add the WebSocket server to the same server environment that you use for your remix app. remix really exposes the underlying web server that is used when you use remix. If you pick the Express.js adapter, you have access to where the Express app is created. And in there, you can also just add a WebSocket server. It's just a node.js environment. And now if you pick the right deployment target, you can have your WebSocket server run next to your remix HTTP handler. What is really cool about this is with remix, we were so happy that we can share code and types between our front and the back end. And now with this, we can also share code between our WebSocket server and our remix application. But we're a little bit more limited because we can't deploy to all the environments that remix supports because we have to make sure that this environment also supports WebSockets. That brings me to my last pattern here, which I'm most excited about. And that is to use server-side events as an alternative technology to WebSockets. So we use server-side events now to create a connection between the front end and our server that creates this full reactivity. And the way server-side events work is that they create a one directional stream between the server to the client so that the server can send packages like information or events to the client. So it's not bidirectional like WebSockets, but if you really think about it, the other way is already covered with remix. remix provides everything we need to mutate our server state based on our client state. So this forms and form submits and use fetch. We can already mutate data. And then since remix out of the box revalidates our client state and synchronizes our client state with our server state, the only thing really that is left is to inform one client if another client changes the server state. This is what full stack reactivity in that sense means. On the full stack, on the server, if you change the state, your client reacts to these changes. And with server-side events, you can kind of ping your client and inform them of a change. And then you can trigger revalidation or the payload can even include the entity that has been updated. And then you manage that in react state. So what's really cool about server-side events though is that you can actually implement them inside your remix application. So inside a resource route in the loader of your remix app, you can add the code to create a server-side events endpoint. And then you can just use the platform on the front end side of your remix app and a user-factor as react to create the connection to that endpoint. And now you have full stack reactivity and real-time capabilities for collaborative multiplayer experiences in your remix app today. remix doesn't really provide any primitives and conventions to handle that, but since remix exposes the platform for us, this is supported basically out of the box with remix today. And I think it's just so cool. So we have three real-time patterns here, how to implement real-time capabilities with remix. You can use WebSockets in one way or the other with remix. And even more, I'm even more excited about server-side events. And there's been also a lot of traction right now around this topic on GitHub on the discussion about server-side events and remix. And I'm just really excited to see where this leads. But at the end, I want to leave you with one fact from the survey, and that is that six out of the 74 participants, it's around 8%, stated that they started programming with remix. I think this is just a great opportunity for all of us to create beginner-friendly content for remix. I personally would have loved learning programming or web development with remix. It probably would have helped me to understand the platform better before jumping into react. Now I feel like I'm thinking a lot of times in a react way, even though I want to think in a web way. And I think remix would have provided a great way to get started with this. But that just means we all have a job to do right now, and that is to make the community more approachable for beginners. That said, thank you so much for listening and happy coding.
23 min
18 Nov, 2022

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Workshops on related topic