This week Steph's taking a quick break, but while she's off, Chris is joined by a special guest - Jonathan Reinink. Jonathan is the creator of Inertia.js. Inertia.js lets you quickly build modern single-page React, Vue and Svelte apps using classic server-side routing and controllers, and listeners of the show will certainly have heard Chris rave about it on previous episodes.
Chris and Jonathan dig into what makes Inertia unique as compared to frameworks like Phoenix LiveView, Laravel Livewire, and Rails' Hotwire & Turbo. They also discuss how Inertia embraces the URL, the unique "protocol" nature of Inertia, and how to consider Inertia alongside native mobile applications. Throughout the conversation, Jonathan's consistent philosophy of wanting to build robust, performant, and delightful applications shines through.
- Jonathan Reinink on twitter
- Eloquent Performance Patterns
- Church Social
- Jonathan on Full Stack Radio
- Foundational blog post: Server-side apps with client-side rendering
- Laravel Livewire
- Phoenix LiveView
- Hotwire Turbo
- The Inertia Protocol
CHRIS TOOMEY: I am seeing what I believe to be the relevant things.
JONATHAN REINIK: Let's dance.
CHRIS: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Chris Toomey. And this week, Steph is taking a quick break, but while she's away, I'm joined by a special guest, Jonathan Reinik. Jonathan Reinik is the creator of Inertia.js. And listeners of the show will know that that is increasingly one of my favorite frameworks and, frankly, just ways to build applications on the internet. Jonathan is also the creator of the Eloquent Performance Patterns course, which teaches the Eloquent ORM, which is the ORM in Laravel but really digs into deep performance and database things, so really covering that back end as well. Jonathan also collaborated on the development of Tailwind CSS, a utility-first CSS framework which again is something that I have spoken of in very high terms on this podcast. And lastly, Jonathan currently runs his own SaaS business called Church Social. So really, Jonathan is a bit of a quadruple threat covering back end and front end design and entrepreneurship. So pretty much everything you want to see. And frankly, I've been so impressed by the breadth and the depth of Jonathan's work and just the deep way that he is thinking about building applications. So I am absolutely thrilled to have him on the show today. So without further ado, Jonathan, thank you so much for joining me.
JONATHAN: Thanks so much, Chris. That was a very kind introduction, and yeah, it's awesome to be on The Bike Shed. I've been a long-time listener, and as I've said to you, I really appreciate the support that you've given to my work over the years. So yeah, it's awesome to be here.
CHRIS: That's interesting. We're measuring it in years now, but it's a very sincere thing for me. I think with Inertia, you've built something that is both very unique and a special approach to how we build things, but it's also built from very familiar pieces and allows us to reuse the deep amounts of knowledge that we have in the Rails community or the Laravel community. But actually backing up just a little bit, because we're going to dive deep on Inertia.js today, for folks that are not as familiar or have only heard me mention it in passing, there's a wonderful episode of Full Stack Radio where Jonathan and Adam Wathan talked about Inertia.js, and I think gave a very good foundational summary. So we'll link to that in the show notes in case anyone wants to dig in a little bit more. Likewise, Jonathan has a really fantastic blog post called Server-side Apps With Client-side Rendering, which, as far as I can tell, is the manifesto that began this whole journey for you. And I really love that you have done so much of the work in public, and people can see the history of how this idea has evolved and really crystallized into what now is a very production-ready framework in sort of the way to build things. But I would love to hear right now just for anyone who is not as familiar and also just to hear how you summarize it at this point in time. What does your introductory elevator pitch for Inertia.js sound like in April 2021?
And I totally get the need for those style apps and the place for those style apps. But I really missed this way that you could build an application with Rails or with Laravel where you could just literally spin up a new app, create some routes within your server-side framework, create some controllers, create some views, and have a working application within minutes really. You could have something being displayed on the screen within minutes with these classic monolith applications. And if you wanted to do the same thing, if you wanted to get an app up and running in minutes with Vue or React as your completely client-side SPA scenario, it just wasn't working because as soon as you say, “Well, in order to do that, you're going to need to have a back end Rails or a Lavarel application, and then a client-side Vue or React application. And then you're going to have to create this API that connects the two together.” There's just a lot more work that goes into that. It's not only the work of actually creating the API; I find a lot of the decisions that come along with building an API; it’s like, okay, what does the abstraction look like? Am I going to build it with REST, or am I going to build it as a GraphQL API? And all the decisions that come along with designing and architecting that which again has its place. But there's just something awesome about saying, “Here's a new route. Here's the view that I want to render. And here's the data that I want that view to have,” and just go off and do it, and it's done.
And some people ask me, “Well, with Inertia, if you're not building an API, what happens someday if you need an API?” And they frame it like, well, this is a terrible decision. You should be starting with an API. But for me, the reality is that so many of the web applications that I was building and that I've seen other people building is they had already made the decision not to use an API because they had already made the decision that they wanted to use Laravel as a monolith app that had their controllers and the routes and their views all within that and the same thing with Rails. So if you've made that decision to build a monolith app with Laravel or Rails, you've already made the decision to not build it with an API. I was coming in from the other way. It's like, I just want to build an app the way I've always built in Laravel, and I don't want to have to build this API. Of course, there are times where you do need an API, which I think we're going to talk about maybe a little bit later if I don't ramble on too long, where it does make sense to have an API. But yeah, that's kind of the elevator pitch.
I think maybe to close off that thought is that I really, really enjoy having a tight coupling between my routes and my data layer and my views, which, again, I appreciate that. That probably sounds like blasphemy in modern web development. But for me, I think it's so empowering when you say, “Hey, I have a controller that's given me some data, and I have a view that's rendering the data, and those two know about each other, and those two depend on each other.” You can work so fast because I'm not thinking, okay, well, I have this API endpoint that returns a user, and that has their first name and their last name and their email. But I also need to think about it in the situation in the future where I might need this attribute or that attribute or some other attribute and make sure I have all that figured out ahead of time or at least have a way to add it in later. And all of that thinking that goes into designing an API, I find that that adds a lot of overhead.
And then maybe related to that also is the amount of times that you're rendering a view within your application that needs data from multiple different places. And to me, this is like one of the huge performance benefits that you get with a tool like Inertia is with, say a REST API, GraphQl solves this, but with a REST API, you're often getting too much data for what you actually need for the page, or you're often making more than one HTTP request because you say, “Well, on this particular dashboard, I need some user information. So I have to hit the user endpoint. I need maybe the latest product sales data, so I need to hit that endpoint.” And you’re dealing with these performance issues that you get with a REST API that with Inertia, you don't have that problem because it's just going back to classic Laravel Blade views or Rails and ERB templates. Am I saying that right, ERB template?
JONATHAN: In those situations, you say, “Well, if I need data from three different places, well, I'll just grab data from three different places and send it to the view, and that's fine. And I can do that in the most efficient way and get the data that I need specifically for that view.” So anyway, that's some of the thinking that drove me to build Inertia and some of the things that I was going for. And yeah, it was an evolution. It really came out of me using Turbolinks and really appreciating what Turbolinks gave me but taking it to that next step where it's like Turbolinks, except it's built with the same principles as Turbolinks but built for modern client-side frameworks like Vue and React.
CHRIS: Yeah, that all feels very familiar to me. And in my experience, I've now worked with Inertia on a handful of projects, but in particular, I have just a small personal app that I use to manage different aspects of my life. And it's been my playground for different technologies. And I've migrated it through a bunch of different versions where it used to just be a Rails app. And I was like, oh no, the thing that I need to do to be on the cutting edge is to turn this into -- it's a Rails app on the back end with an API, and then it's a React app. It's separately deployed, but those two talk to each other. And what you were talking about of the deep coupling, I think that coupling exists whether we want it to or not. And so embracing that and revisiting when I eventually migrated that application to use Inertia and the client-side stuff folded back into the core codebase. Now deployments all go out in sync. And that turns out to actually be a really nice thing and a non-trivial thing to solve otherwise.
As a developer of one on this particular project, the amount of complexity that was removed from the app when I switched it over to Inertia was amazing. I got to remove client-side routing. I got to remove client-side state management, which I think I was using Redux at the time. I got to remove some form helpers that I had. I think I might've been using Formik or React Use Former, any of those. But there are so many different little pieces that you ended up cobbling together to make an application. And it was amazing to me as I moved to Inertia, where I was like; actually, I don't need any of those, and routes suddenly are defined in one place in Rails in a familiar way. But things like redirects all work -- It feels just like a Rails app but with the extra abilities that a front-end client-side framework gives you when you want those when you need those. But otherwise, it really does feel like I'm rendering to an ERB template. It just happens to be that that template is rendering on the client-side and is written in React or Svelte or whatever the front-end framework is. But it almost feels like progressive enhancement. I'm borrowing a term, and it's not actually applicable here, but it really feels like that. It's like, oh, it's a Rails app, but I just want to make it a little bit fancier, and Inertia does that in such a fantastic way.
And actually pivoting just a bit, as far as I can tell, there seems to be an explosion of thinking in this space. There are a handful of frameworks, namely Laravel Livewire, which is often paired with Alpine.js. Elixir has Phoenix LiveView, and then Rails has the Hotwire suite, which Turbo and Stimulus are the most pointed considerations. But interestingly, I think all of those frameworks, which I think are trying to provide a very similar experience, tend to keep things on the server-side, so using the Laravel Blade templates or the ERB in Rails. But you've taken the different approach to say, “No, let's embrace this front-end technology where it makes sense.” And again, there are a lot of pieces that can fall in, and I don't need the Redux and the React Router and all of those things but still use that client-side framework to be the rendering engine. And so I'm intrigued if you can talk a little bit more about that and that trade-off because I think it really differentiates Inertia and its approach. I personally found it to be fantastic, but I'd love to hear a little bit more about your thinking on that.
CHRIS: It's on the rise. That’s my long [inaudible 14:46]
JONATHAN: Yes, and people keep saying that. So anyway, Inertia basically said, “Hey, we want to keep building server-side apps. We want to keep building monolith apps similar to these other tools, except what we're going to do is we're going to embrace the fact that there's this really, really amazing tooling that's been developed for the client-side.” And it just doubles down on that. So for me, the reason that I ended up here was because, in my own SaaS application, it was a Laravel application that started with mostly Blade views initially. And then, over the years of building it, which has been many, many years, I've slowly added more and more Vue components within my app. And initially, the way I did it is those Vue components would just be inserted in as regular HTML tags in my server-side rendered templates. And then, when the page renders, those Vue components would boot up and do whatever they need to do. So for me, when I was building Inertia, I had already fallen in love with Vue, in particular, and having all the power of these client-side frameworks. And there is so much there. It's not just Vue, React, and Svelte; it's all the amazing tooling that's available out there that you can add on top of it.
And this is the thing I often tell people that Inertia isn’t -- we say right on the homepage, “Inertia isn't a framework.” And the reason why I say that is because I don't want people to think of Inertia as an alternative to Vue, React, and Svelte. Do you know what is a better way to frame it? It's actually more of an alternative to React Router or Vue Router; that's really more what it is, where you can say, “All my routings are handled server-side,” and that has all kinds of interesting implications. But it's more of a router, and it just so happens to pass along that routing control over to the server. Anyway, so that's really for me what differentiates Inertia from those other tools is because it's really doubled down on these client-side frameworks.
And I think the reason why Inertia has been relatively popular is because people know Vue and people know React. And when it comes to then working with Inertia, it's not some new thing that they have to learn. It's an existing set of tools that they're already super comfortable with. And in so many ways, when you're building an Inertia app, you're kind of building a classic Vue app or a classic React app or a classic Svelte app. It's just there's a bunch of pieces missing. Like you said, it's like a bunch of the client-side state management stuff, which nobody likes anyway, is gone. The other thing that's gone is client-side routing. You don't have this back-end routing is over here now, and client-side routing is over here, and I have two different routing definitions. It's like, no, that's all just server-side now in one place.
The other amazing thing you get is you mentioned redirects and that whole HTTP layer you get just along with Inertia for free because it's just part of your server-side stack. And one key aspect of that is auth. You can just use good old-fashioned nothing is better than session auth. Like, it just works. And, so whatever your typical solution for doing session auth in Laravel or Rails or whatever server-side framework you're using, all this stuff just works. So anyway, coming full circle on your question, the reason why Inertia has gone this way is because I really think that there's a huge amount of value with using these modern frameworks. And we just doubled down on using them.
CHRIS: Yeah, that resonates with my experiences using Inertia and in contrast to the other frameworks. Everyone seems to be trying to get to the same place of providing a mechanism to have more almost app-like functionality but still using the traditional server-side technologies. But I think Inertia has chosen an approach to that that is unique in that category and really has provided a fantastic outcome. I've been very frankly surprised by the fidelity of experience and how app-like I can get something to feel when building with Inertia while still using all the same technologies. And the fact that I can use just traditional server-side auth and redirects and things like that is just so nice, and everything feels right.
There's an experience that I've had on many applications that are, say, a React client-side bundle that gets sent down and then boots up, and then the layout starts to render. And as its data fetching, it gets like a 402 response or something like that in that data fetching. And then it's like, oh no, I need to hard redirect you over here on the client-side to this other page. And there's this junk of semi-filled-out layout, and then suddenly you're on the login page. And again, with Inertia, it looks like a normal server-side rendered app, but it isn't in the ways that really matter to us. And it is one of those things where the more I played with it, the more there's an experience of interacting with Inertia that it surprises me consistently how nice it is to work with it and yet it's so much easier to maintain an application using it. I know I'm raving here, but I am really a big fan of this for everyone listening in the audience.
CHRIS: And actually to continue on one of the things you were saying there, one of the things that stands out to me in Inertia is the way that it embraces URLs and to a certain degree, that seems like a purposeful thing, but it also seems like it just naturally falls out of how Inertia works because we're no longer using a client-side state management technology, the way to manipulate state is through the URL. If you want to see a different version of the to-do list you're looking at when you click on that link, you change the URL and the state changes in response to that. And so everything is fundamentally kept in sync, but URLs are very much at the center of the architecture, and I really love that so much. I think URLs are often forgotten in client-side frameworks or underserved or underused. And it turns out in my experience as a user and both having served many users, people love to command-click on links. They love to right-click open a new tab. They love to be able to reload and see the same thing on the screen when they reload the page. They love to be able to bookmark. These are all really wonderful things that come out of working on the web. And the fact that Inertia has a pit of success around having URLs and have that be the way that we drive state is just so fantastic. So I'm wondering how much of that was very purposeful on your part versus how much of that fell out of the architecture.
JONATHAN: That is very much something that fell out of the architecture. I say that not to say that I don't value URLs; I absolutely did. That's the way every single one of my Laravel built apps worked. It always starts in the route file. You hit the route file, you define a new route, and it goes from there. So I absolutely think that the URLs are critical. But the fact that it just ended up working out so nicely was, yeah, I'm going to say it was a bit of luck, a bit of coincidence. I find this is what's so interesting when you start pushing on a new way of things; you initially don't really know where it's going to end. It’s like you have some ideas of how the tool can work and where it might go, but I think there's a lot of unknowns that you just figure out after a while. So the thing I said earlier actually about the fact that Inertia in a lot of ways is like a client-side router; it’s, it's a routing library, to put it that way. I had been working on Inertia for a year and a half, and then a buddy of mine, Taylor Otwell, the creator of Laravel, he and I were chatting, and he said to me at one point he's like, “Oh, you know what? Inertia is actually super simple. It's really just a routing library.” And it was like, bam. It was kind of that moment; it’s like, oh yeah, I hadn't thought of it like that at all. But when he said that, it made a ton of sense to me. So it's just this interesting progression the more you work on something, and the more you push on the edges, you learn what's possible and what it even is.
I had this interesting experience, so remembering that Inertia came from Turbolinks. So I had my whole app built with Laravel ton of server-side rendered templates with Blade with view mixed in. And I had the SPA mode by clicking around using Turbolinks. So when I decided to try building Inertia, I removed Turbolinks, and all these requests now happened over XHR but using this preset JSON structure that powers Inertia. I really, in my mind, had this idea that it was only for GET requests, for GET visits; it was just for that. So the initial version of Inertia, there was no Inertia.post or Inertia.put or anything like that. It just wasn't something I even thought was possible. But then I remember, and this is often how it goes; I was out for a hike that day to get away from the computer for a little while and just let your brain drift; I'm sure you can relate to that. I was like, wait a minute; I could totally just support POST, PUT, PATCH, DELETE. And that was such an aha moment for me where I just realized that it was so much more than what I originally thought it was.
And then the whole thing from that I remember it was a bit of like a waterfall effect after that where I remember running home out on that hike and hacked it together, and then it was like, okay, well, if I submit a form using POST, well, okay, I'm on the create user page. And I submit this form using Inertia.post to the user's endpoint. I'm like, well, how do I now end up back at the user index page or whatever page, maybe the user edit page. I’m like, wait a minute, I can just return a redirect back to the user index page, and it's literally going to return an Inertia response from the user index page. And then the way Inertia works is it dynamically swaps the page component client-side. And it was just like, oh, this is way too cool. And this really drives my thinking now that it's become a little bit more clear to me is that it really it's all based on HTTP using headers and normal HTTP stuff like redirects are such a critical piece of the story. But to me, that's super neat that, in a way, it's like a throwback to the fundamentals of the web and the browser and the fact that Inertia can just use those things,,, and it doesn't have to be fancy in a lot of the ways. It can just rely on those existing core pieces of the browser. So, yeah.
CHRIS: It really is interesting to me how it feels like progressive enhancement in that way where you're building on top of these core fundamentals of HTTP and requests and redirects and status codes and things of that nature. Particularly interesting to me was it took me a while, I'm going to be honest, to figure out forms and particularly validation errors in Inertia. And that is entirely my fault. You have absolutely fantastic documentation. I am so impressed by the quality and the density of the documentation that you have that really covers everything. If we're being honest, I hadn't read the page, but I was doing form posting and then the subsequent errors and how you deal with that. I was doing it in a very traditional Rails way which if we're being honest, that is not a fundamental of how HTTP works. Rails just chose an option of oh, if you POST but we don't create the object because there's a validation error, then we're going to stay on the URL of the POST, so the collection route, but we're going to re-render the form in line. And that's a choice that Rails made that is interesting because at that point, if a user reloads the page, then things are weird, and it's not going to reload. They're not going to see the same thing after that reload, or it's going to try to repost or et cetera, et cetera. There's a bunch of edge cases there that sort of fall out. Whereas with Inertia, you end up redirecting back, and there's this interesting handshake of the errors, but from an end-user experience, it is absolutely fantastic where you stay on the form; the URL does not change. Technically, there's a POST and a redirect back under the hood, but Inertia just handles all of that for you. And you end up with sort of in-line validation errors. But you don't clear out any fields, and there are just wonderful things that fall out of it that again took me a while to get there, but it was another one of those oh, wow, this just naturally falls out of the architecture, but it's so nice and such a nice incremental advance on top of frankly, the stuff that I was doing in Rails historically.
JONATHAN: So the way that Laravel works and it's always worked this way is when you make a request using POST or PATCH or DELETE or whatever to an endpoint, and that endpoint does its validation in the event that that validation fails, this is just like built-in standard like Laravel Stock behavior. It automatically redirects you back to the endpoint that you were on. So if you're on the create page or the edit page, it automatically redirects. That's just Laravel behavior. And what it does is it takes those errors that come out of the validator, it flashes them to the session, and then when the forum page reloads, you have those errors available to you in the session. Now, of course, if you're building like a classic server-side rendered application and you redirect now back to your form, you have to repopulate old form inputs, which is not a lot of fun, which you don't have any of that stuff with Inertia because Inertia allows you to preserve your state. But anyway, that's a separate thing. But for me, it’s like you build a tool a little bit like in your own silo and the world that you know, and for me, that's Laravel. But there are also ideas that you get that just come from the tooling that you use, and the fact that Taylor Otwell made that decision in Laravel at one point is absolutely what now dictates how is the go-to way to do it in Inertia, just because it works so nicely.
CHRIS: I wonder if there's been any consideration in the Rails world to adopt that because I think from an experience perspective, it feels like it's a better thing. It feels like it has the same robustness and guarantees that I would expect. But yeah, that's interesting. It makes sense that that was just naturally there because, again, it didn't feel like the obvious correct thing that Rails was doing. It was always a little bit odd and so interesting that Laravel was already there. But then Inertia can take it that one step further. But taking a slightly higher level view of all of this, one of the things that's really interesting about Inertia to me, especially in contrast to some of the other frameworks that we've been talking about like the Livewires in the LiveViews is Inertia is almost at its core a protocol more than it is…it's a sum of pieces, and with Inertia, you have a server-side adapter, so there's the Rails adapter and the Laravel adapter. And then, on the client-side, you have a separate either Vue or React or Svelte. So those are the officially supported ones on both sides, but there's also been a swell of community support. And so there's a Django one, which I'm not sure if it's currently maintained, but I just saw a Clojure one the other day. There's a Java Spring Boot. So those are all server-side adapters. I haven't seen as much on the client-side, but I imagine there are at least a handful of them out there. And it's so interesting to me that there's this core idea that you define this protocol of communicating back and forth from the server to the client and now this collection of things that are growing around that. And I wonder again, how much was that purposeful versus how much did that just happen? And then further to add a second question to complicate things, how are you thinking about managing that community? Because my sense is that this could allow for Inertia to be so much of a bigger tent and really bring in the best ideas from all of these different communities and end up with something at the core of this Inertia thing that is the best of every community and all of that. So yeah, a lot of questions there, but I'll hand it over to you because I'm super interested.
JONATHAN: So I think when I first got going, it was Laravel and Vue; those were the tools that I worked with. And often, the best software and the best open-source software in my mind comes out of trying to solve something for your own needs. So that's really where Inertia came from and specifically for Laravel and Vue. But I quickly realized early on that it didn't have to be just a Vue and Laravel thing. So intentionally early on, I had this idea of trying to build it with multiple adapters, and I had this idea that you could build as many server-side adapters as you want and as many client-side adapters as you want, and maybe we'll officially maintain a certain amount of those, which is what we do right now. We officially maintain the Vue, the React, the Svelte adapters. And then, we also maintain officially the Laravel and the Rails server-side adapters. So that was, I would say, pretty intentional. And it's crazy how many server-side adapters people have been able to put together. Somebody wrote a ColdFusion server-side adapter for Inertia. I had no idea ColdFusion was even a thing anymore; yeah, legit. There are node ones; there are Phoenix ones; if you can believe it, there's a WordPress one, which I'm not even totally sure even how that works. There is ASP.NET.
JONATHAN: Like, there's a whole bunch of them. And it's actually despite of me, not because of me, that this has happened because I am yet to write a good here's how to build an Inertia server-side adapter in the language and framework of your choice guide. It's been on my to-do list. I have a bunch of things I want to do. So it's still something I want to write, but people what they're doing is they're just reverse engineering what we're doing in Laravel and Rails and these other adapters, and they're figuring out how to do it in their own server-side language and framework. So that's been really, really cool.
On the flip side, on the client side, I'm starting to realize more and more that that's actually where the most important work for us as the maintainers of Inertia that we need to focus our efforts on because it's non-trivial to create these client-side adapters. And for us, we actually have four of them now because we have React and Svelte, but then we have Vue 2 and Vue 3. And they're different enough those frameworks that we actually had to create a separate adapter. So that's really where all our work is. The core of Inertia is actually ridiculously short, like the whole file, like the whole core Inertia adapter is 150 to 200 lines of code. And maybe it's a bit more than that, but it was that for a long time. It might be 300 or 400 now. It's very short. Even honestly, the client-side adapters are pretty short too. It's just that it's more difficult to make these client-side adapters because you get to learn all the intricacies of how each one of these frameworks handles their rendering. The core behavior that Inertia uses is the fact that you can dynamically swap components. So we dynamically swap page components when you visit from one page to the next and the details that come along with that.
Anyway, so I’ve realized that moving forward, my job is going to be to make sure that the client-side adapters are awesome and then letting the community drive the server-side adapters a little bit more and providing some better guides on how to do that. But yeah, for now, it’s like if we can get it working in Laravel and Rails, we should be able to get that functionality working in any server-side adapter. And because it's all again just based on HTTP, that's the language, that's the protocol like you say. That's the thing that matters between all these web frameworks, which they all, of course, support since they’re web frameworks.
CHRIS: I think you're not giving yourself nearly enough credit for the support that you've given to the server-side frameworks because you do actually have a page in the documentation called the protocol that does a great job of at least summarizing it at that HTTP level. But at the end of the day, again, like the job of someone implementing it is to then map that into their given language and framework of choice. But yeah, the documentation is impressive in just how much you put in there and how much care you obviously put into it and lots of nice, subtle details that are covered very well in that. So that again, if you read it, unlike me, then you get to know everything; eventually, I got there. I think I've read the whole thing now. But there's a lot there, and you cover all of the details.
But actually looping back to a topic that you hinted at earlier, but this is something that I've been pressing up against lately is I absolutely love building web apps in Inertia, but there's often the need to bring in a mobile app, and we want native mobile for various reasons. I love the idea of progressive web apps, and I want to push that envelope as much as I can. But as an example, right now, iOS does not support push notifications to PWA. So if that's a key feature that we want, then we're dead in the water or if there are certain GPS things. There are a bunch of true platform native things that we just can't get. And so I'm now contemplating building out an app alongside my Inertia web stuff, but I want to build a React Native app, and I'm wondering, to a certain degree, does this invalidate some of my ideas? I know you hinted at this earlier, but I think I'm still convinced of the utility of Inertia on the web. But I think I need a different paradigm to build for a mobile app, and I'm trying to decide where that line falls. I'm also wondering if I can just get away with embedding a bunch of web views and reusing my web logic because, again, if I'm building all of this, I'm going to build it in a mobile responsive way. I don't want to rebuild the core page functionality of my app just to put it on mobile. Maybe mobile folks would tell me I'm wrong there, but I'm interested in maybe wrapping it and getting access to those platform features. But yeah, I'm interested in what your thoughts are there.
JONATHAN: Well, embedding a web view within a native app has been proven to work just as DHH, obviously. But yeah, there are definitely people who disagree with that approach and feel like you should build a legitimately native app. Let's say that we're going to legitimately build a real native app. We want to have an Android and iOS app. So I actually ran into this myself for my own SaaS application, and I solved it by building a native app using React Native so React Native obviously being an abstraction on top of iOS and Android and all the tooling there, which is such an amazing platform. It was just a real joy to work with. And I don't even hardly work with React, and I was able to get a nice, high-quality native feeling app built relatively easily. But I had to come to grips with this very question because, like I've been saying all along like, “Inertia is great because you don't need to build an API. Yay, this is amazing. This is what you should do. Oh, crap. I need an API.” And I had those questions like, okay, well, does this invalidate everything that I've been doing? So I was thinking about it, and in the end, what I did is I just built a light API alongside my Inertia application. So what it is is I think I have seven endpoints, and they're just REST endpoints that are designed specifically for my native app. And this works honestly so well.
And I think I've explained to you a little bit in a previous conversation, so I'll repeat myself a little bit here for the benefit of the listeners. The reason why I think it's completely legitimate to have Inertia and build your entire web app that way and then have a companion API alongside it in the same monolith app (let's be clear: it's in the same application. It's in my Laravel app, or it would be in your Rails application) is because it just extends a core principle for me of what Inertia is. And that core principle is a tight coupling between my data layer so my controllers, and my views. So if we take that thinking where we say, well, Inertia in an Inertia web app when we have an endpoint, we hit the controller, we load data from the database, we pass that very specific data to the view, which is Vue or React or Svelte and it renders it. And there's a very tight coupling between the two. And I treated my native app in the exact same way. I said, “Okay, I need an API because obviously, the native app on iOS and Android has to make an HTTP request to get this data somehow. But instead of trying to create this super generalized API that could theoretically be used for anything, I use the same principle that said I'm going to allow myself to create an API that has a really tight coupling between the screens in my native apps and the actual data that's coming from those API endpoints.
And this worked out really, really, really well. I don't have to deal with a lot of the issues that you run into when trying to create a more generalized API because I could just say, “Hey, I have this calendar page, and I want that calendar page in my particular app. I want it to show people's birthdays, and I want it to show wedding anniversaries, and I want it to show custom events and these things that we have called schedule reminders.” So it’s data from four different endpoints. I didn't try to say, “Well, I'm going to go and create now my event’s endpoint, and my birthday's endpoint, and my anniversary's endpoint, and my schedule reminder’s endpoint,” and now have all that work to do in my native app to okay, we'll hit all these different endpoints and merge it all together; it wasn't like that at all. I created a calendar endpoint that returned all the data that's needed for that screen. And I basically applied that thinking through my whole native app, and it was really a joy to work this way. So I think that approach works really well if you have an app that doesn't have complete feature parity with your web app.
And I think if you had a native app that needed absolute feature parity between the native app and the web app, then my thinking might be a little bit different on this. But in my experience, so often, native apps have a vastly reduced subset of the features that the web app has in particular, even if not for the core functionality of the application but just for the administrative side of it. There's a whole bunch of stuff that you tend to have in a web app around administrative stuff that you literally never need. And I mean administrative both in terms of it's a multi-tenant style app, which most apps are so in terms of the user's administrative functionality and in terms of the system level, the software owner administration. If you build your whole web app to be built on top of an API, all that administrative stuff that really doesn't need to exist in both places, you now have to make it exist in your API because you've made that decision to build it that way. Whereas if you just stick with Inertia on the web and just build it using that classic monolith way where you get data from the controls and send it to your Blade views or in this situation, client-side page views, and then you just expose the stuff that you actually need natively, for me personally, it's worked out so well. And if I look at my own web app, the amount of controllers that I have for the whole web app, I have like 100; it's a very big app. And for my native app, I have about 10. So that was like, I'm so glad that I didn't have to create 100 of these in both places.
And then some people will be like you might be thinking, well, now I have duplication. I have duplication in some of my API endpoints and my web endpoints, and that's true. I would say first that duplication isn't always a bad thing. I think more duplication in our web apps would actually probably lead -- I feel like we run away from duplication too quickly. I don't think duplication is as bad as software developers often think it is. But even then, if with the duplication you can't live with yourself, there are still ways to solve duplication. So Laravel, for instance, has this concept of they're called API resources, which is basically they're essentially transformers. You give it some models, and it transforms that model into some other states, some other design. So there's nothing stopping you. And I even did this myself within my server-side application within Laravel to have an API resource to have a transformer that's used by both my Inertia controller and my API controller in a couple of situations and for me, only when it makes sense. I'm not going to do it all the time because I found that most often, I wanted the data in a slightly different format in my native apps than I'd want it into my web app. So quite often, that didn't happen. But I'm just saying if you're scared of duplication, there are totally ways to solve it. And we can solve this in our existing frameworks. Laravel or Rails has ways to allow us to abstract some of that stuff and reuse it in multiple places. So, yeah, that's my long-winded answer to how I've approached doing the native apps sort of thing. I think that tight coupling between the data and the screen I think that's a really nice thing, and you just can build faster. And just like you can build faster with Inertia on the website, you can build fast [inaudible 43:19]
CHRIS: Frankly, that answer makes a ton of sense one and two, makes me feel better about the path that I'm on because, again, I'm really desperate to cling to Inertia for the web side of things. So I love what you're saying. And again, it really resonates with me and how you're thinking about building. There's also I really appreciate a subtle common theme that I've seen in a bunch of things that you've said where you're like; let me poke at best practices a bit and see what falls out. What if we were to actually embrace the coupling between our data and our view layer? And it's like, actually some really nice things happen there. And actually, going back to an earlier project that you worked on, Tailwind CSS is one of those projects that when you first see it, you're like, well, that's obviously wrong. That's definitely an incorrect way to do things. But then you explore it, and you're like, well, I mean, I know there are trade-offs here, but actually, in my experience and I'm sure in your experience, Tailwind is absolutely fantastic. And the trade-offs you totally win in the long game, and it's maintainable, and it's understandable. And you can continue to develop on top of it in a way that I've never found with any other CSS framework. But again, at first glance, you're like, ooh, that's not right. That can't be right.
JONATHAN: 100%, exactly. I think it's fun to push back and just experiment with different things. And for me, I think a lot of my decisions, too, come back to the fact that I'm running a SaaS application as one person, and I need to be able to move fast. I don't want to have two different servers and two different repos. I want to be able to build my applications as fast as I can, as a single developer, a single founder. And so I think the things that I push against and try and experiment with come out of me trying to find the simplest ways to maintain things. So Tailwind, that's really Adam's brainchild. I came along in the first six months or so; me and him built it. I was really just helping him flesh out his idea there, and that was super fun. But yeah, I had the exact same experience as you. Adam was telling me about this, and I'm like, that sounds pretty terrible. Like, I have CSS figured out already. And then it was like, oh man, this is amazing. Fun little fact, my SaaS app, me and him, were both working on web apps at that time. So my SaaS app was one of the first Tailwind applications ever because I and Adam were literally both building our own apps while building Tailwind CSS.
But anyway, so yeah, it comes out of not me trying to be like, I know better than other people; it's not that at all. It's more just I'm trying to find a way to survive as a business and trying to build at the same time, not only survive but also I want to build awesome products. I don't want to build software that is just kind of okay. I love striving to make software that's just exceptional that delights people that works the way someone expects it to work. And I just think that there's so much broken software out there. There's a lot of bad software. And don't get me wrong, I've created a lot of bad software, too. But I really try to hold myself to a high standard. And really, for me, that comes down to not necessarily what some purist says that “This is how you need to do it.” It comes more down to like, okay, let me see the results. How fast does the webpage open? What's the performance? You mentioned my course earlier. I’m really, really interested in database performance and how to use databases more intelligently to deliver really fast web applications. And that matters to me because customers hate waiting. They hate it. And that was even part of what drove me to create Inertia because I hated this. I was working for a company, and we had built the right way where we have an API and the client separate And we went down that road. And that was a big team with 20 to 30 developers in the end. And I was just like -- I shouldn't say, “I was,” but we, in general, were not happy with what happened because just the way that the app was built and the way that single views were hitting the API. You could probably argue that this was like we were doing something wrong, but the paradigm didn't lend us to doing it right, in my opinion. So we'd have pages that were hitting the REST API with sometimes 10, 20 HTTP requests just to get the data. And you're dealing with all the loading states of all this stuff. And of course, there were probably better ways to design, but we were trying to ship a product there too. We were trying to get it out the door and make happy customers. And I didn't feel like that way was helping us.
I think GraphQL, just as an aside, is a huge step forward where you can say, “Hey, here's all my data in an API, but I'm not going to hit the user's endpoint just to get back whatever you decide to give me.” I can be much more intentional about saying, “Hey, I want this data and then pull in this relationship for that data and this other piece of data.” And I think that's really, really cool. But I think the problem there again is you need to build that GraphQL API, and that's non-trivial, not to mention you probably have to figure out OAuth, which is pretty much always a game-stopper for me because if I never have to work with OAuth in my life [laughs] I'll be totally okay with that. I know it has its place, but yeah.
CHRIS: There's a clear passion and a desire that you're describing there to just build good things and the belief that it can be done. And then, as someone who has really benefited from your work, I thank you for carrying that torch and for pushing the envelope. And like you said, having that high standard and holding yourself to it but then hopefully bringing the rest of us along, and I really appreciate that. But I think with that, that's probably a perfect time to wrap up. If folks want to follow more of what you are working on, where can they find what you're up to on the internet?
JONATHAN: I'm on Twitter, the classic place to go for following someone in tech, so twitter.com/reinink, my last name. That's R-E-I-N-I-N-K. So that's where even if I have stuff shared elsewhere on the web, that's where it starts.
CHRIS: Perfect. We'll include links to your Twitter as well as everything else that we've mentioned in this episode in the show notes. So folks that do want to keep up or investigate further listening to that other podcast episode that I mentioned will have all of that available. But with that, thank you so much for your time, and yeah, again, really appreciate you joining.
JONATHAN: Thanks so much, Chris. Pleasure to be here.
CHRIS: The show notes for this episode can be found at bikeshed.fm. If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. If you have any feedback for this or any of our other episodes, you can reach us at _bikeshed on Twitter. Or you can reach me @christoomey, or you can e-mail email@example.com. Thanks so much for listening to The Bike Shed, and we'll see you next week.
This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.Support The Bike Shed