Tom Preston-Werner is building a full-stack framework for React and GraphQL developers. In this episode we talk about RedwoodJS, a framework that's bringing full-stack to Jamstack. Tom is a co-founder of GitHub, creator of Jekyll (the OG static site generator), TOML, and Semantic Versioning. If you've been hunting for a full-stack React and GraphQL solution, and envy the integration of frameworks like Rails and Laravel, listen up, because RedwoodJS might just be for for you.
Tom Preston-Werner — Twitter, GitHub, Website
chantastic — Twitter, GitHub, Website
Join the discussion Discord 🎉🎊🥳
Listeners of React Podcast are chatting on Discord!
Join us Thursdays at 10am CT for a friendly chat thru the latest episode.
It's fun, interactive and all are welcome!
AWS Amplify is the fastest, easiest way to develop web and mobile apps that scale.
Get started building a React app today, check out the tutorial on AWS Amplify today, visit awsamplify.info/react.
In over your head with a React or React Native app?
Infinite Red can help.
They are React Native core contributors who've been designing, building and shipping apps for over 10 years.
Learn more at reactpodcast.infinite.red.
Please join us in donating to the Equal Justice Initiative
Chantastic: Tom Preston-Werner, welcome to "React Podcast."
Tom Preston-Werner: Thank you. Thanks for having me. Excited to be here.
Chantastic: I am super excited to have you on the show. Just on a personal note, more than anything, I'm excited to have someone on the show who is, for the last 10 or so years, influenced the way that I work as a developer. I'm going to gush for a second.
You're the founder of GitHub. You created Jekyll, SemVer, TOML, Gravatar -- things that impact my life on a daily basis. On behalf of anyone who's listening, whose life you've also impacted, thank you so much for being here and talking with us today.
Tom: Thank you for saying so. It's absolutely my pleasure. I love creating things. I love bringing value to the world and making other people's lives easier. I'm a developer, and it brings me great joy to be able to help other developers have more enjoyable lives. I'm absolutely pleased to have done those things for you to enjoy them and to be here to talk about stuff.
Chantastic: This year has been like a funny year and I feel you're the person to talk to you about...
Chantastic: I forgot about all the other things because I was just thinking about React for right now. Yes, it's been a chaotic year. At the beginning of the year people really started to ask me a lot, I went on a couple of podcast talking about...If you were to build something today, what would you reach for?
If you're going to build a product, not just some type of front-end for an existing product or an integration or UI, if you were going to build the product. What would you reach for? I feel, in React, I've not had an answer for that. It's always been I would probably reach for something that I know pretty well like Rails, Laravel, or whatever.
As I've had those conversations with people on this show or other shows, Redwood keeps coming up. It wasn't until recently that I got a glimpse as to what this is, but you have built one of the flagship Rails apps in GitHub. Now, you're building a framework to bring some of those full stack ergonomics to React.
My big question that I want to kick this all off with is, when you have so much muscle memory and power in the tool of Rails, what is it that inspires you when you're building your next product, your next service, your next startup to sit down and start thinking about a framework from the ground up?
Tom: The journey for me from Rails to wanting to work on Redwood and build a new framework started gradually. ChatterBug is the current startup that I have for language learning. We started it out with just plain vanilla Rails.
I hadn't used React much before, but he started building things with it, and I started to dabble with it and learning React. I was just blown away by how much better the paradigm of building front end with React is. There's jQuery over here. That was what I was used to. Then there's React over here and...
Tom: ...I'm like, "Just delete all of the jQuery stuff, like immediately." Everything new has to be done with React, and I just started getting into it and loving everything that everyone loves about React. Which is it just simplifies the way that you build front-ends. It compartmentalizes it. You get the one way data reflowing when you change stuff.
It's the dream that I always had, the thing that I always wanted when I was writing front-ends. In jQuery you're like, "Let me fiddly find this thing by ID, and then change the text. React is like, "No, just change variable," and just like, "Boop."
Tom: I was like, "Oh yes, I need that." We started using more React. Then over time we started feeling like, "OK, we had Rails on the back-end, just not now." It was just delivering JSON to the front-end. Then the React component would...We had a page and it would just suck in the JSON, and it would do the whole thing.
It was still the Service-side basically doing all the work of data processing, giving that to the front-end, and doing it. They were like, "Well, it would be really nice if we could break up our data fetching, and get different things at different times so you could have a page load incrementally."
Then we started pulling in GraphQL, and so now we ended up with a Rails app that was just a GraphQL API. That's mostly what it looks like today, for most of the site. Everything new that we're doing, it looks like that.
We're not that new at the time. Maybe a year before we started working on Redwood which is already like a year and a half or almost two years ago, around functions. Netflify, they launched a feature called Netflify Functions where you just have a file in your Git Repository that you want to deploy to Lambda. They will then do that for you.
You have just a single code file. It represents your Lambda handler. You push it to GitHub, they suck it in, they deploy it. They'll deploy your static stuff to their CDN and they deploy your function to Lambda for you.
I saw that and I was like, "These are now the building blocks that you could use to build a full stack application if you're thinking in the React way, which is I have a static React client that can be delivered via CDN."
It's available everywhere super fast. That's going to talk to Lambdas which, theoretically, you could have distributed everywhere. That could be the business logic. In the case of Redwood, you wrap up an entire GraphQL API into a Lambda and deploy it into Lambda. Then, the database is the hard part.
It's still the hard part because this JAMstack mentality of how you architect this and deploy it was created almost antithetically. JCL was really in the early days of that, at the very beginning of this sort of getting away from databases. It's maybe a little ironic that I'm now like, "Hey. Databases again with the JAMstack."
Maybe I'm a hypocrite but sometimes you need a database. If I'm building an application, a web app, I need a database. I can't do everything I want to do in the content...I'm not going to use JCL to build a web application. That's just not going to work for me. Doesn't make sense.
Chantastic: It's truly fascinating to me because you've been on both sides of this. You have JCL that is, as far as I recall, it's the OG of static site generation, but then, you also have these super dynamic sites on Rails. It's really fascinating this experience that you've had because I've seen it repeatedly.
At some point, you're doing so much on the front end, so many API calls, you're redesigning your RESTful endpoints specifically for your new front end code. At some point, you're like, "What is Rails really getting me besides doing this stuff in Ruby which is a weird language anyway. [laughs]
Tom: I think Meteor was too early. They were maybe even the right solution, but just too early. This happens sometimes with technology. You can have the right technology at the wrong time. You have to remember also the time that Meteor was around, there was no package management system. They had to build literally everything themselves. They built like a hosting thing for it.
Just from my own personal experience, I remember reading about Meteor and being like, "This seems really cool but I feel like it's too locked in." Those impressions weren't even true and maybe that was a problem with the marketing, but my perception of it was that if I build a thing with Meteor, then I had to pay for this other thing. It didn't feel as open source as I wanted it to be.
That's just for me why I never really ended up playing with Meteor. The lessons there, it was too big of a leap. It was asking people to abandon everything that they knew. Everything. It's like, "Oh, you do Rails? Guess what? Literally, nothing is the same." Everything changes.
"If you want to build a full stack web application, then guess what? I'm also going to give you Prisma and I'm going to integrate that really well and give you scaffolding like Rails has, for easily building out your initial interfaces.
Chantastic: [laughs] See you on the other side. Tell us what you made.
Tom: You're on your own. Now you're like, "Oh man. I got to figure out how to do everything." You have to make a million choices and then, everyone's React-based application ends up being completely different down to the file structure.
You show up with a new company and you're like, "All right. I'm ready to get started on your React web app." Then you got to spend the first week just figuring out where files go because everyone does it differently.
Chantastic: Yeah, and all the local conventions. Absolutely.
Tom: Redwood is, in a lot of ways, just standardization. If Redwood is anything, it's standardization and integration. What we say is, "We do all the hard work for you. We configure Webpack for you so that you don't have to, so that you can focus on your product." Which is exactly the same thing that Rails did 20, 15 years ago. 20 years ago almost.
Chantastic: One thing that I think maybe a little bit different about Rails is there's this huge mindset of convention over configuration. Is that right?
Chantastic: I got it right.
Chantastic: This whole mindset, that's the big thing. They leveraged Ruby quite a bit to actually make that happen and to infer a lot of details based on naming of things and the place that they live and what not. I'm curious, I know that that can be a hindrance a lot of times in adapting a framework.
Tom: We don't really talk about it because that idea of convention over configuration has just permeated software development so much that it would be weird if it wasn't that way for any project where you're like, "The first I have to do is write 100 lines of config." I guess Webpack is a little bit that way, but they've made that a lot better, too.
You can get started with Webpack really easily but once you get into Webpack, it's like, "Oh man." You got to really understand what it's doing. You got to watch 10 hours of video on the internals of Webpack to do certain things [laughs] but that's because it's such a powerful...That's what Webpack is for. Webpack it so that you can do anything in the build process.
For Redwood, we don't really talk about it. It's just the way that it is. It's just there. There is minimal configuration. There's configuration where you might want it but there's defaults. Today, we think of it more that we just have the same defaults.
That's the common expression of convention over configuration. What it has become is same defaults. Your project better have same defaults or nobody's going to use it.
Chantastic: I know and I listened to an episode of Friend First where you talked with Sam [inaudible 15:30] and Ryan Torano. You were talking about how can it can be really difficult in a long-lived Rails app or a Ruby app, to be more honest, where things happen at levels that you don't really understand and you can insert a preference at a level that's really hard to find.
It was the Ruby to get bindings so that we could read the Git repository from disk and Ruby turn it into Ruby objects and then be able to express those to the front end through Rails. I went out and I asked Chris Wanstrath, one of the co-founders at GitHub, if he wanted to join and help me build the Rails part of it because I didn't want to build the Rails part of it. There's too much complexity and magic there for me.
I wanted to write a pure Ruby library where I had complete control over everything and no one was trying to do a bunch of fancy stuff for me. I honestly don't love as much magic as there is in Rails and I really, really dislike metaprogramming functions like cobbling functions together by iterating over strings and defining the functions based on the string names.
I have a very low tolerance for that level because it makes it impossible to find anything. Your search becomes useless. I don't love that. To me, it makes it hard to maintain things. The magic and the automatic loading of things can get...That's probably a bad example because that's actually really nice.
Tom: You know Rails, right? There's a lot of hidden things.
Tom: The framework itself is...How much code is in the framework of Rails? It's a large amount. Redwood is pretty minimal. The weight of Redwood itself is really low. We do very few magical things for you.
There's a few things that we do around cells which are the declarative data fetching. We do a little bit of automatical loading in the routes file because otherwise if you have 200 routes, you have 200 import statements for every page components...
Tom: ...that you import which I didn't like. That's just a little thing. It's like, "Oh, you don't have to manually import them." That's it. It's magic, but it's like the 20 line code file that does that in webpack, it's in Babel now.
Everything's in Babel now, which everything could come out of webpack as much as possible. It goes into Babel, so we can support TypeScript properly. I like having less magic, I like being able to statically analyze my code for the most part.
That is a valuable thing. Ruby is inscrutable, to build tooling around Ruby is almost impossible because of the metaprogramming.
Chantastic: This is something that has struck me in my very limited exposure to Redwood, through the tutorial is that it has an explicitness that I really like and I almost want to say tasteful magic. There's tasteful little bits of magic. I can see how that's valuable. I don't want to the way that you're using workspaces is a good example of that.
Instead of having to navigate down to that root directory and then back up to whatever you want to import just you've got a workspace for it, source, you're good to go. It does feel there's a lot of things that help with the ergonomics, help it feel framework-y, but don't feel this big top down.
We know all the ways that you should be building a React app. It feels very much a React app that I have full control over right out of the box.
Tom: You can this is the thing. Redwood's not going to prevent you from doing or using any normal library that you would want to use. It's like you want to use state management library, Redux, a Recoil, whatever, MOBAC, go for it. We don't have an opinion on that currently. We might in the future, but we currently don't or CSS framework, we don't care.
There are some choices that we decided that we couldn't make because they would be too restrictive for people. If you say like, "Oh, in a Redwood app, you have to use Tailwind's CSS." Anyone who didn't want to do that would be like "This framework is not for me."
Whenever those questions would come up, if there was an answer where someone would say, "Redwoods, not for me because of that choice." Some of them are basic choices, like, "Oh, you're going to use React."
Honestly, that's not even necessarily one. Right now, we have chosen React as what we use for our web side. In Redwood, there are sides. There's the web side, which is your frontend, and then there's the API side, which is your backend.
For the web side, we've chosen React, but there's no reason that we couldn't in the future create a different web side that used Vue. There's nothing fundamental about the framework that would prevent you from doing that.
It's just a technology choice that we made because that's what we were working with, and that's what we like best, but you could imagine doing that because, architecturally, a Redwood application is a statically deliverable frontend that talks GraphQL to GraphQL API.
The sides don't even have to be the web. From the very beginning, and the reason that we use GraphQL, and focus on making it really nice and easy to build a GraphQL API, is because it means that you can build a client in anything, and it means you only have to build your API once.
The common pattern has been, for a long time, anyone who started with the Rails app is like, "OK, Rails, boom." You got your Rails app. It's all server side, delivers your generated HTML to the browser. You're done.
Tom: You're like, "OK, sweet! We're going to build it with whatever." You want to start using GraphQL. Maybe, you chose React Native. You use GraphQL, or you use anything. You want to use GraphQL, because GraphQL is amazing. Now you're like, "OK, crap." I guess, we'll build out...
Tom: ...GraphQL API also in the Rails app or even if you are doing RESTful stuff, you're still building out a whole separate bunch of RESTful end points. The dream that Rails had where it's like, "Oh, your pages are all so RESTful," and like that. I don't buy it.
Chantastic: [laughs] I've never seen anything that doesn't end up having some amalgamation of APIs that are like when you have to actually start serving customers through an API.
Tom: They are different. You iterate on them differently. They get versions separately, they are just different. They are different things. If you're going to do it for real, you're building a separate API. If you're doing it in REST, it's a separate thing. If you choose GraphQL, obviously, that's a separate thing.
Now, you're building out this totally separate API. You've got your main site in Rails. That's feeding out web pages. You've got an API that your clients are going to use. Everything that you build you have to do twice. Everything you build, right?
Tom: If your mobile client is doing all of the things that your web client is doing, guess what? You're essentially building it twice. You're building in one place, you have to hook it into two different places.
Anyway, the complexity is increasing. I don't like that because that's what we ended up doing at Chatterbug. Guess what? Rails site, normal stuff, also GraphQL API. Now we got to do things twice. Learning lessons from that, in Redwood, we say, "Well we can build mobile clients all day long and it's great actually."
They perform really well. They're resilient to data issues because they're cellphones. They need to do the things that cellphones do. They're optimized for performance. If that's a totally normal thing to do to build a mobile app that way, then why are we not building our web apps that way? It's not really any different.
Then we can just have everything read from a GraphQL API and then my back end is literally just a GraphQL API. Now I only have to build things once.
Chantastic: This is really interesting because there is this notion of, "Hey. I want to decouple my front end and my back end." Unfortunately, what we've seen is that that makes it really terrible developer experience a lot of times especially if you put stuff into server-less which is, historically, it's getting better but been really difficult to develop against locally.
You build this front end and I feel like GraphQL came in and helps out a little bit, but it's always felt super fractured. The really interesting thing that you're doing about Redwood, you talked about sides, is that you have the web side, you have the API side, but you're developing them together and you've built a framework around building them together but with extensible sides.
It's not just these two sides forever. You're building them separate but together so that you can build as many of these sides that you need.
Tom: Yeah, and it's all in the same repository. A Redwood repository is a monorepo. It's actually two projects. We use the yarn so we have workspaces. The workspaces come from yarn. Then you can operate on them independently. When you build, you have different environments because the target for the website is a browser and the target for the API side is a node runtime.
The problem, and some people are trying to do things where they erase this difference where you pretend like it's all one thing, but the reality is it's not all one thing. The code that runs in the browser and the code that runs in node on some server somewhere must have different restrictions. They have different performance characteristics.
Mentally, you're just doing different things. I think you can get the illusion that that's going to help you out. That it's like, "Oh look how easy it is to pretend that these two things are the same." Next has this sort of philosophy where it's like, "Oh look. They're the same." It's like, "They're not the same."
I don't want you to tell me they're the same when they're not the same. I'm a developer. I'm a responsible developer so I need to know what's going on. Stop trying to confuse me about what runs where. Redwood is like, "You know what runs where."
Chantastic: [laughs] That is interesting and I feel like Next, over this past year, has really backed out of...They used to be the same exact API calls and now they're backing out of that a little bit so you have certain calls that run on the server side, certain that run on the client side.
You can attack them different which is exactly to your point where, as a developer, you know that they're different and you don't want to have to pretend that they're the same thing because they're not.
Tom: I get confused enough as a programmer. I don't need additional layers of confusion.
Chantastic: [laughs] I want to back up a little bit and cover some of the parts of Redwood. We talk about Redwood but what are some of the technologies that it actually uses to accomplish the goal of providing this full stack JAMstack type of development experience?
Tom: Technology-wise or you'd like Netlify stuff? What do you mean specifically?
Chantastic: Technology-wise because you mentioned Prisma is one of the tools that you're using, GraphQL. Those types of things.
Tom: As I said before, it's React client on the front end. React and you would choose probably some way to do CSS. You might choose some way to do state management, but people do that less now with hooks. Things have become a lot simpler. That's your React front end. Then, the API, right now we use Apollo. We like it for the most part.
It's pretty heavyweight on both the client. It's more important on the client to be light. Apollo3 actually reduce the bundle size nicely which we love. Bundle size, this is always a performance concern. This is a concern that we have like we build new technology and we find out this thing is amazing and now, this thing is worse.
We use Apollo client on the front end, Apollo server on the back end, and then, Apollo server to build the GraphQL API. There are some little bits of magic there that make building your GraphQL API way easier than you thought it could ever be.
You should go do the tutorial. If you want to check out what I mean by that, go do the tutorial on Redwood. It's amazing. It's the best tutorial you'll have ever done.
Chantastic: It's very good. Absolutely.
Tom: You build your GraphQL API but you're not even thinking about Apollo. There's nothing there that's Apollo-specific. We could swap that out with something else if we wanted because you're not doing anything Apollo-specific in the back end.
In there, if you want to connect to a database, if you want a full stack application which is probably why you're using Redwood in the first place, you're going to use a database. We use Prisma which is a query builder. It's like an ORM. They don't want to call it an ORM. It's kind of an ORM but it's not. It's just delivering you back like a data structure.
Also, at devtime, we've integrated testing with Jest and Storybook with Storybook. Those two things are integrated and part of the dream of the development flow. Maybe initially you're not using Storybook as much and none of us write as many tests as we should, as responsibly as we should, but you always want to feel you can.
Where these things really shine is when you start getting a little further. A dream that I've always had for 10 years, since the GitHub days, one big problem that we always had was, you have some piece of a page that's deep inside your site that's behind auth and it only comes up in certain circumstances and you're trying to work on it.
You're like, "I got to get my database into a state where it's going to show this page and then, I got it logged in as this kind of user that has these characteristics." You spend half an hour just setting up the data to get you there and then you're like, "Finally. I can see my code and write it."
My dream has always been to be able to write web front end code without it being in my application. If you are familiar with Mustache or friends, that was a concept that I stumbled...I didn't write Mustache but Chris did, Chris [inaudible 31:41] , co-founder.
That came from a conversation that we had in a bar where I had come across this library that Google had called Ctags. It was this logic-less templating language. I saw it and I thought, "This would be really cool because it would allow you to build all your HTML and stuff, and you'd have just your data bits that would be templatized in there."
It's logic-less but you can do Boolean stuff in there. Then, you could develop in an isolation. This was 10 years ago that I was thinking about that. I'm thinking about how cool that would be and Chris took that and created Mustache. I created this entire universe of templating stuff. Twitter uses it now.
Handle bars, those are the same ilk of things but I was always chasing this idea that if you could develop chunks of your web application outside of your application, it would be so amazing. Because then, the other thing you could do is change the data and be like, "All right. This Boolean is true, here's the name and here's the whatever." Just fill it out and it would be like, "All right. Here's what your thing looks like."
Guess what? Guess exactly what that is today? Storybook. React makes that possible. Storybook makes that possible and it's the most amazing thing. Once you're into it and you're like, "All right. I have to design a component that is a flag." Like on Chatterbug, we have language flags and there's a bunch of them.
You're like, "OK. I'm going to develop this flag thing. I got to make sure it works right. It's going to have these seven flags. They got to be able to render in these four different sizes based on these parameters." We use Storybook and it iterate over these three sizes and these seven flags and just show them all to me.
It's just like [beep] . I can go in there and change anything and it's just like [beep]. That's beautiful. I don't have to make my app show me a French flag in medium size and then be like, "All right. Let me fiddle with that."
It's the culmination. These technologies now are the culmination of this dream that I've had for like a decade about what developing a web application could be like. All these different ideas that I've talked to so many people about over so many years are finally coming together and deployment. We haven't even talked about deployment.
Chantastic: [laughs] I want to gush on Storybook for a little bit longer because that was one of the things that I was super excited to see when I went through that tutorial. Use the generator and it was like, "Boom. Home.stories.js." It was like, "Holy cow. This is exactly what I want because of exactly everything that you described."
One of the things that I hate about working in full stack apps is that nobody ever thinks about how you go back and modify that thing. You have these situations where it's like, now, every designer on your team has to be at least a little bit full stack in order to munge the data in the database to get the flag to show up or the user type to show up and all of that.
It's such a waste of expertise and energy to have to do that every time when you can just say like, "Hey, I have tests for all the states. If the data is there, it's going to look like this."
You shouldn't have to go in and actually dive deep into a database to be able to just make a design change or make sure that an authenticated user looks this way and an admin looks that way or whatever. It's nonsensical that we've had to work this way for so long. [laughs]
Tom: I know. It's so beautiful. That's what React really is to me. That modularized, parameterized, like, "Take this data in and show this thing." You can consider that thing totally isolated. I mean in practice, it's often not. For the most part, it's this encapsulated thing.
You got to fiddle with stuff that comes in via context, which is the crappiest part, but there's things in Storybook that help you deal with that. Or the part where it gets really hard is when you start doing data fetching in your components, because you're like, "I would like my components themselves to do data fetching so that they can load asynchronously and separately." Now, you're screwed in Storybook.
Tom: You're like, "Well, crap. My thing's going to try to go and talk to a GraphQL database, a GraphQL API somewhere. Now what am I going to do?" Guess what, we saw that in Redwood with a mocking. We used Mock Service Worker. It's beautiful. You just create a file called whatever.mock.ts.
It represents what data you would want returned in your Storybook. As long as you hook it up right, and it's super easy, then it'll just pull that data and will use that data to show you your thing. If you're using Cells, the data fetching stuff in Redwood, you can easily, in Storybook, work on your Cell by using the mocking.
Chantastic: Wild. I love it.
Tom: That's what we mean when we talk about integration. It's thinking about all of these things that would be amazing if only you spent the time to really integrate them well, to create this developer dream. That's what we're trying to build.
Chantastic: You see a lot of this trying to go into design tools. Figma, maybe, has some integration where you can connect to your GraphQL server and get data like that, but this is actually happening in the product. It's not like some separate face. You can actually do that same thing utilizing Cells and stories. That's amazing.
Tom: And testing. You use those same mocks in testing. You use the same mocks across your tests so that you can also test and get whatever mock data you wanted. You have multiple different mocks, but there's a default mock that Storybook will use.
It's annoying to tell Storybook all the time what you want. If you just want one thing in Storybook for it to do to make sure it's going to come back with the right stuff. You can have multiple and you can tell which one to use. You have to add another one code but the same mocking behavior works across [inaudible 37:44] testing in Storybook.
Chantastic: Nice. I want to cover some of the language. Then I want to get to deployment for sure. I want to cover some of the language because we've talked about Cells and sides. I want to make sure that everyone knows the thinking behind those as we go into them or as we continue to talk about them. Cells, tell me precisely what those are with regard to a component and data.
Tom: A cell is our primary way of doing data fetching. The normal way in React that you would do data fetching for GraphQL is you declare the query that you're going to run and then you execute your query.
Then, that's going to have a loading state, and it's going to have a success state. It's going to have a couple of different states that it goes through. You're going to have a big conditional statement.
Your component, that's going to be...When it's loading, show this thing. When it's successful, do this thing. What we didn't like about that was how it messes...The code gets messy. You're putting all those things in the same embedded in this big conditional statement inside your component.
It's not very pretty. It's not a very nice pattern. We started thinking about it and we were like, "Well, all of these things are components." What if you were to be able to declare them so that you could say, "OK. For this component, here's what the loading state looks like."
Have a file where you export that. You'd be like, "OK, export. The loader looks like is this component." Then export success is this component and export a failure is this component. It takes props in and spits out a component."
What if it's a list? What if you're doing a list query and the result is empty that's another state that you have to deal with. It's like, "Oh, in that case it's this other component."
That's what Redwood cells are. It's a veneer almost. It's a little bit of magic, but a cell looks like a component. The way that you name. It just ends with cell. It's like userlistcell.js.ts. It just exports these different things.
Also, you define the query and you export the queries. The export query equals whatever your query is. You can also modify parameters that come into it with a before query thing and modify the data that comes out of it. That is then going to get passed to success.
It's basically an Orchestration Layer that's declarative. Then, we run the query for you. We're like, "OK. You executed the query," so give me the query. I'm going to run the query. Then, during the different states, I'm going to grab the thing that it needs.
I'm going to like, "You export it a loading components, so give me that." Then, you'll see that for a second. Then, "Oh, I got a success. I got some data back, so give me the success component and I'm going to give it the data that I got back."
You might want to change in between the results of the query and giving it to the success component. You might want to change it. There's a little call back in there that you can do and after...What do we call it? After query? I think we call it...It's like before query after query. Maybe, I forget now, but you can change the data before it gets to the query after it comes out of the query.
Chantastic: Oh, interesting in case you need to munch it or change little bit for that specific component rendering.
Tom: If you need to do a little bit of modifying of the structure to reorganize it from what the GraphQL gave you, to what you really want to take in from the success component then you can do that. That allows you to really think about what you care about you like, "I'm working on the successful state of this component."
Like, "Boom here you go," here it is, nothing around it, is just the success component it takes in props and outputs what it needs to and you're not looking at all this other crap that's around it, this big conditional
Tom: You just don't have to worry about it. This also thinking long-term. This allows us to be in the GraphQL call so that we could do interesting optimizations in the future because instead of you running it right so you're doing the actual query call to Apollo client.
A abstracts Apollo out, so that if we did want to change the GraphQL client we could without you having to change your code because you're not doing anything Apollo specific in this case and it puts us in the middle we're now the middle man for the request response which means that as we start thinking about how to solve problems the waterfall problem.
Where you have a component that fetches of data and you have subcomponents it's going to want to fetch and complete that data request before it gives it to his children. The children might not care about anything that first parent query is doing it might only need the ID the user something.
Now you have to wait and then it finishes then it passes down the children because it's just the way that React renders. In the future we might be able to optimize the way the GraphQL runs to parallelize things wrapped they can combine things up do whatever we wanted to because we're in there, we have control over that process. That's what sales are.
Chantastic: It's one of those little tasteful bits of magic that I like because as a designer is nice to just pull off the one state that I need and focus on that and then also what you said to be able to opt into optimizations without having to concern myself with the changes to Apollo and whatnot.
You've taken the work of having to know what those tools are that connect you to the database out of the way completely. That's now a framework concern and I'm sure that there's ways which you can dive into it, but like you said, you're going to get optimizations by not concerning yourself with that.
Tom: Yeah. That's the beauty of something that is declarative is that you're just saying like, "What do things look like? What do you want it to be?" Instead of running it yourself, instead having all the imperative code around, do the actual query here's the query and then deal with the different states.
You just saying what you want at the end of the day and you let me...The framework. I'll take care of it. You just tell me what you want.
Tom: I'll take care of it.
Chantastic: Love that. That sells and that's great little distraction around those concepts because we've all seen components like this. They all look the same, they all look gross and it's really nice the way that you've organized that so that these components can be very clear and declarative.
Now, before we jump into services, let's talk about sites. This is a interesting construct that you have and the two that Redwood ships with when you build a new Redwood app are going to be Web and API. Tell me what is the notion of a side the abstract notion of a site.
Tom: The sites really are just how we break the main pieces of the app up, and right now there's only the two, there's Website and API site. Conceptually, it's the API site which is the primary one, your application is a GraphQL API and it may be consumed by one or more front-end client sites.
Right now, we deliver a React based Web side. That's just because we started with Web apps. Web apps are the easiest thing to do. A lot easier than a mobile app, a lot more useful than a command line interface for instance or a kiosk app, or a car, something that runs on the dashboard of a car, whatever you would consume something from, some IoT device.
The Web app is the standard, easiest place to start in that's what we were interested in so that's why we call them sites. That's why their distinct, and that's why we use GraphQL in order to communicate between them for that flexibility.
Eventually, we would love for Redwood to have a setup. It's like, what do you want? What are you building? Are you building a website? Are you building a mobile application? Are you building a command line tool? Are you building something else?
Have all the Redwood goodness, for not just building a web client in React, maybe we'll have the ability to write a web client in View or something else. You want to build a Native client with React Native. We will almost certainly offer that at some point down the road, because that's such a natural fit.
You can reuse a lot of stuff between your web app and your mobile application if you're using React. If you write them in the right way. It's tricky, but there is reusability. Even if you're just copy pasting, and then modifying that. Whatever. It's still easier than writing it from scratch with Swift or something.
Maybe we even have a Swift based front end too. Why not? I don't know. If it speaks GraphQL, we can help you do it. That's what Redwood wants. Just wants to give you the ability to focus on your product and not worry so much about your framework.
Chantastic: I'm curious you've mentioned having a possible View website. If someone liked the notion that you're after with Redwood, but wanted to do it in Preact or View or some other type of thing. Are the pieces there right now that they'd be able to maybe plug in to that and build their own side pretty easily?
Tom: We haven't spent a lot of time abstracting out the notion of sides. I think we've done a little bit. Peter has done a little bit about that, but we haven't spent a lot of time because it's not our main concern right now.
Our main concern right now is get a 1.0 out. I'd love to do it before the end of the year. We got a lot to do still. We haven't tackled SSR Pre-render type stuff yet, which is what we're really focusing a lot on right now.
There's some big things that are really essential for 1.0. The concept of sides and future of Redwood helping you do that is a little bit further off. We don't make it easy, but it's not going to be too difficult, I think.
There are some assumptions that is like, "Oh, you have a website. You have an API site." Right now, you can actually not have a website. You could just delete the web folder, delete the API folder and Redwood is like, "OK, I'm cool with that." Right?
Chantastic: I'm pre-React app now.
Tom: All right.
Chantastic: With Storybook. [laughs]
Tom: Right. You still get a lot of the benefits on the front end. You get Storybook and testing and all the things that we help you do there, integrating just beautifully with these different things. For instance, we're working on this app called Repeater. That's it. repeater.dev. It's the URL. That's a background JobScheduler for the JAMstack.
One of the problems that happens when you start deploying to something like Netlify is guess what? Where do you run your scheduled jobs? There is nowhere to run them. That's what Repeater is for.
Repeater is a place where you can create one time, scheduled jobs that will execute immediately, or would execute at some arbitrary time in the future, or recurring jobs that would be more like a cron type of thing for doing data aggregation or whatever.
If you're just sending an email, you do a one-time thing and you're like, "I don't want to wait for my email to send in band. Tell Repeater to schedule that." The job of Repeater is to make an HTTP call back to you and you can create custom functions in Redwood very easily that will just be lambda. Just for lambda functions.
Repeater can just call back. It gives you the payload and then you use the rest of the framework in the normal way. You use the rest of the API in the normal way and you can do whatever you need to do when it schedules to call to you. Send emails or make some change in the database or do whatever you want to do.
My point was with that is Repeater actually has no back end itself. It's a Redwood application with no API, because Rob Cameron, who's another core member of Redwood, built it as a Rails app, because he wanted to use delayed job. So repeater dev back end is Rails that is using delay job, because he knows that super well.
He's like, "I could just spin this up and we could make this thing work." He's like, "All right. Go do that."
Tom: The Redwood front end with no API talks the front end, instead of talking to the Redwood API. There is no Redwood API. It talks to the Rails app, and that is the authoritative data store. It works really nice, because it's just GraphQL.
Tom: It is all GraphQL man.
Chantastic: [laughs] Rob camera is in chat right now. He says, "Hey, that's me." [laughs]
Tom: Awesome. Here I am.
Chantastic: [laughs] I know that.
Tom: I don't have the chat up. I can't see it.
Chantastic: [laughs] No, it's great. That's one of the big questions with front end applications and JAMstack and all that is you have these things. We didn't even talk about jobs. Rails is good at giving you services and wrappers around being able to delay jobs.
It's really cool to hear how you're still using some of those services, but you're hiding them behind, obscuring them a little bit. You don't have to use a full stack framework just to leverage those pieces.
Tom: Yeah, that's the JAMstack serverless way. You have a variety of services that someone else is going to manage for you, because you don't want to manage them.
Tom: Things like background jobs is one. Uploading files. There's a bunch of services where you could use to upload files, because it's like, "I don't want it. I don't want to manage that."
Tom: "Honestly? Really? Do I want to manage uploading your files to S3 and dealing with that in my database? No, absolutely. Just give me an ID and go. You store them wherever you want and I'll know how to pull them down and you deal with it. I'll pay you to do that."
This is the serverless architecture aspect that is the JAMstack. This is the normal JAMstack way to do things. You can use those third party services, and integrate them into your app and now you don't have to deal with that.
You don't have to build that. Billing with Stripe, you want to do store inventory and store stuff, or Shopify, or uploading files with File Stack, or dealing with your background jobs with Repeater and now you can collect these services.
As the core, you still with Redwood, you have a full stack web application with a database, and you're doing the things that you care about most. The things that are specific to you because guess what? Handling uploads of files and storing files is never ever going to be the thing that my business does or cares about.
Tom: That's always the thing that I have to do in order to make my product. I don't want to build that. That's not my core value. How can we help you focus very specifically on your core value, and let other people handle the thing that is their core value so they care about it more than you ever will?
Tom: You just pay them a little bit of money to do it for you. In the end that ends up saving you money in the long term because you're hiring fewer developers. What's always the most expensive thing in building a company? It's always the people.
Chantastic: Yeah. I love this because there's a huge amount of pragmatism built into the documentation and the notion of Redwood I'm very much attracted to, and really is focused on building a product, getting a product to market, focusing on your core competencies and maybe at some point down the future, in 10 years or whatever you might want to own image and file uploads again. Maybe. Probably not.
You're not restricted from doing that, but there's a very pragmatic way of just like, "Hey, what you need to do right now is build the application, build the product, build the service so that people would want to use your thing, and you should delegate as much of the other things as possible."
I really like that about the JAMstack philosophy. There's so many great services. What services can we use to get to market way faster?
Tom: Absolutely. This, I think, segues nicely into deployment, where Redwood makes it super-easy to deploy to Netlify. You can create a Redwood app. You still need to spin up a database somewhere, and we're working on ways to make that a lot easier.
Netlify, maybe, will help you set up a database and get it running, and then you just hook it directly to whatever. It's not a big deal. Right now, you got to spin up a database somewhere on DigitalOcean or Heroku or AWS, wherever you're happiest with. Then, your Lambdas are going to connect to that.
That's beautiful. It's easy. A single command, the migration Prisma will handle the migrations for you, if you're using MySQL, Postgres. It's just beautiful. Your client is on a CDN, the Netlify CDN for instance, superfast, globally distributed.
Then your business logic is going to be deployed to Lambdas. Right now, this is a restriction with Netlify, in that they've deployed all Lambdas to the USEast1 in AWS.
Tom: The roadmap there is...It's like they're going the direction where it's going to be. Eventually, they'll let you choose where you want them or their auto will distribute them around the world or whatever. Now you could have your Lambdas around the world, right?
Tom: The last part is your database and having distributed relational databases is still pretty challenging and expensive, but I'm excited about things like Fauna. FaunaDB is a NoSQL but properly serverless and globally distributed. It fits the Redwood use case super well, only that there's no Prisma adapter for it yet.
I think they will. The plan is to do it eventually. I want to use the query language FQL. To do it and it's still not quite as easy as I would like it to be, but you can see in the future that eventually there will be choices for these globally distributed serverless relational things. I hope someday, but just...Relational databases were never built with this in mind.
Tom: They've got a restricted number of connections that you can make to them...
Tom: ...which is totally not the serverless way. Fun is, "Talk to me via HTTP all day long. Great, as many connections as you want. We'll handle it. Queue them up."
Chantastic: [laughs] We got it. We're good.
Tom: All good. MySQL is like, "I have 20 connections, so be careful."
Tom: You're like, "No, what do you do?"
Chantastic: Use them wisely.
Tom: If you put your business logic on lambdas -- guess what? -- you could have an infinite number of lambdas. You could have an infinite number of connections. Now you have to add connection pooling.
There's still some things here that are not fulfilling my long-term dreams of what Redwood can be. That's why we're here to push vendors to make this stuff better. Part of the core thesis of Redwood was, "Let's build this now." Before, the infrastructure pieces are perfect. Once people realize how amazing Redwood is, and we get users...
Tom: ...they're like, "Hey vendors, we want to use Redwood, but your stuff sucks." They'll be, "OK, I'm sorry, I'm going to make my stuff better so that Redwood is better." I have no shame in saying some of these things aren't optimal yet because we're early. We're not media early.
Tom: We're early enough that we can help push the industry where we think it can go.
Chantastic: Interesting. Now, one of the things that you touched on is database. You still have to figure out the database piece of it. It sounds, to me, Prisma is at least abstracting the direct cost of the database for you.
If you're using a Redwood app, you don't have to necessarily on the web and API side of things, concern yourself with SQL or MySQL or Postgres or whatever the actual specifics of your database. That's all going to be abstracted away by Prisma?
Tom: SQL is great. Don't get me wrong. I love SQL.
Chantastic: Sure, but it's another one of those things that's way below product. [laughs]
Chantastic: You can work way higher now.
We went, we looked at a bunch of the ORM'S that were available, and there was a bunch, but none of them really held a candle to ActiveRecord. Active Record is a masterpiece. It is one of the great human achievements. It's amazing how powerful it is.
Tom: "What is this? This is no. This is not. This is not OK."
Chantastic: Yeah, they are all cheap knockoffs. Like you said, it's just a really amazing achievement ActiveRecord. It's a huge part of Rails. I don't think people realize that that is really the masterwork of Rails is ActiveRecord.
Tom: Yeah, it's amazing. It's become so amazing that it almost becomes unamazing in that you can do so many millions of things that it ends up with great amounts of complexity in the scoping that you can do.
You can do really interesting things with it. So interesting that people go into your codebase and they're like, "I have no idea what the hell you're doing with ActiveRecord. This is ridiculous."
Chantastic: [laughs] Yeah.
Tom: It comes at a cost perhaps. What you get in terseness you lose in maybe figure out ability. Prisma was very early. They were super early.
When we came across them, the fundamental architecture they had, how you use and how you define relationships and things, that was finally something that felt like, "Oh, this finally feels like something that could hold a candle, eventually to ActiveRecord." At least it's not making choices that preclude it from getting there.
Chantastic: Yeah, one thing that a lot of people ask us about on the show, I want to make sure we sneak in before we close out this episode is Auth. I know there's a lot of concerns about Auth, React apps. There's so many services. It sounds like Redwood has a very JAMstacky way of handling off. I'm curious what providers you work with right now.
Tom: Out of the box, with Redwood, you can install very easily a couple of different Auth providers, and then have them up and running in a couple of minutes. I actually have a demo of getting Auth running in three minutes. I think it's three and a half minutes.
It's like you go from no Auth to installing Auth. It integrates with Netlify. Netlify identity, and within a couple of minutes, it's like, boom. You're done. You got off the turn Netlify identity. You've got a login and signup box, and you've got stuff in your code where you can test whether someone's authenticated and you can do it all in three minutes.
That's true of all of the Auth providers. We've got Netlify identity, Auth0 and...What else do we have in there? Magic links. You can go to the documentation and see what they all are.
Chantastic: Yeah, Netlify, go through JS, Firebase go for Google Auth provider, Superbase and then awesome options for custom ones as well.
Tom: Yeah, nothing precludes you from rolling your own. In fact, we have a mini framework for building an Auth plugin, essentially, to where you could build your own. Nothing says that you have to use some third party Auth provider and a lot of people don't.
We want to make that easy, but as long as you write it in a way that's going to speak this interface, that's going to talk in this interface, then it'll still integrate with Redwood in the same way that everything else does. You get the advantages of being able to use then the role based authentication system if you want.
You can install one level, which is just tell me whether a person is authenticated at all. It's just like, "OK, the person is who they say they are and now you can make assumptions about whether they can do things."
This would be useful if you're writing something that just has an admin section. Let's say you wanted to write your own blog system, and you want to be able to log in and create posts. Just you. You don't care about anyone else. You might just install it. That first level.
Once you start wanting to have multiple different roles, so you want a person who can edit posts, and someone who can post them and maybe another person who can moderate comments or something.
Now you've got three different roles, and the role based authentication that we also integrate, you just install and import another read with library for doing role based authentication, and now you get the role based stuff where you can test based on what the roles are associated with a specific only user. Some of the providers have that integrated.
With Netlify identity, you can actually store the roles for you. You could also do it where you store them locally. If you didn't want to use their roles, which are very simple, it's just a list of roles. You could store your roles in the database locally if you wanted to do it differently for some reason. We have cookbooks for how to do that.
Tom: All of this to say, you can go from nothing to a fully authenticated application in a couple of minutes. It's just like hooks. It's just like use off. The pull out, you pull out a login function and a log out function, and you can just call them and they'll pop up.
For Netlify identity, you call it login and it pops up the login dialogue and you log in and boom it and then it gives you back your authenticated user. We have the stuff in the site that will fetch that from the backend so you can fill out more about the user on the backend.
When a person logs in, I need the front end to know not only their sort of identifier in whatever provider you're using, but also I want to get their email that I store locally. I want to get some other data about them.
That's going to be shown in a nav bar or something, and there's a way that you do that on the API side where you just fill out an authentication thing and the framework itself knows how to make that call over GraphQL to get the current user information and pull it back.
That whole flow is handled for you. You don't have to worry about it, but it's still really customizable in what you what data you want to be present in that authenticated sort of user data packet.
Chantastic: I really like this model because it makes it easy, but then also you're not tied to one vendor or one style of auth. You have control over all of it but then you can still use the conveniences that you provide through the library, through the framework just to get up and running, get started and maybe take you all the way, who knows but you don't have to think about it at that deep level unless you want to.
Tom: Do you want to build a 2FA system?
Tom: Do you? Answer honestly. No, let someone else do your auth for you. You're going to spend way more money dealing with broken 2FA stuff on your site than you are paying off zero a couple of bucks right every month.
Chantastic: Now back to deployment real quick. What are the current deployment targets? You mentioned a lot about Netlify and the integrations there. Are there other places that can easily right now be deployed to?
Tom: Yes. You can deploy to Netlify. That was the first one. That's what started this whole journey is this idea that we could do full stack on the JAMstack with Netlify and then we're like VSL is not much different. We worked with them and now you can deploy directly to VSL, zero configuration. Super, super easy. That's awesome.
Then we were like, "Well, what if you want to run it yourself on AWS or something?" You want to handle your own Lambda layout, whatever, because Netlify have some restrictions, then you can do that. We have the ability to deploy the currently just the API side to AWS.
You could then hook that up with, so maybe you deploy your front end to Netlify still, but you want to deploy your backend to AWS directly so that you manage it. You can do that. We're working on other types of things a full deploy on AWS front side end, that's AWS and API side. How do we make that possible?
What about far gate being able to run it in a container so that you have no limitations. Right now, Lambda, you have certain limitations around code size. You've got cold starts. You've got a couple of different restrictions, runtime. Let's say you want to have a background job that you want to trigger with repeater that dev, where are you going to run that?
If we make it easy for you to deploy your Redwood app to a containerized thing, then that could be where your jobs run and you can let it run for as long as you want, or maybe you want to run all your backend on far gate so that you have no cold starts.
You just run it all the time or you run 10 of them all the time. You can do that, because it's just there's nothing about Redwood. That is JAMstack specific. It's JAMstack optimized.
Tom: You can run it old school. If you want, you can run it bare metal. Like it's just node. It's just Pollo server at the end of the day. Anywhere you can run a Pollo server and a node process, you can run the API side of it.
Chantastic: Nice. Love that. Loved hearing that. We have just blown through our time today. I want to start wrapping up, but one of the things that I like to ask last is your vision for the near term future. What are you excited about, what you're bullish on for the next maybe three to five years?
It sounds Redwood is the answer to that. I'm curious from you, what are you most excited about putting into Redwood or building into Redwood over the next three to five years?
Tom: It's a little hard to answer. It's going to be what the user, what the community needs. I don't know that I can predict all of that. It's going to be a lot of documentation. There's three things that I really want.
I want Redwood to capture the potential in the JAMstack universe and this new development and deployment methodology, that's one thing that we're executing well on. Number two, I want documentation that is world-class.
We've got a really good start with the tutorial. Rob Cameron, David Price, another core member put huge amounts of work in that Peter, a bunch of external contributors put a lot of work into the tutorial and the documentation that we have, but it is starting to get a little messy.
I want to make sure that we maintain world-class, really deep documentation because to me that's everything. You go to an open source project and you're like, "This looks amazing. I want to use this. I heard about it on a podcast."
Then you go to the website and it's like one crappy tutorial that is totally broken in 12 different ways and that's it. Maybe doesn't even have a tutorial. It's like a read me, but the reading doesn't, it's a couple of code examples. You're like, "I don't even know, what the context of these code examples is."
That person's gone. You're just like, "I don't have time for this." I want Redwood to be like, "Oh, I have a journey." Put me on the journey, tell me how to do, if I want to go deeper, how do I do that?" I'm a, world-class super, world-class, Stripe level documentation. To me that's the bar.
Chantastic: That's the gold standard.
Tom: Stripe is amazing. They kill it on that. I want that. I want a world-class community, like the best community. How do you build the greatest community? It's really hard. We're having to ask ourselves difficult questions about who's in the community because it's not very diverse right now and we're taking steps to try to improve that, but it doesn't happen by itself.
You have to work very hard to make that happen. We're asking the questions about that and talking to people about how do we get the right people here, but it's also a very hard thing to go to people and say, "Hey, do you want to come do free work for me, on my framework?" It's a tricky question.
We're navigating those questions, but I would really love to have a community that people look at and they say, "I want to be part of that community and I can tell how much care they put into it and how helpful and kind they are and how much they want to help me succeed."
That just creates this spiraling sort of value in a community that I don't think you see very often in open source. I think you see it very rarely. I'm wondering if we can do it differently, and we're putting a lot of time into thinking about how we can do it differently. Those are the things from Redwood that I want to see.
In the greater ecosystem, I think JAMstack is going to continue to iterate, improve, and become more powerful and less restrictive. Things like Lambda. What's Amazon going to come out with next? They have all these pieces. How can we leverage those to make developers' lives easier?
In a little bit longer term, I would love to have to care less about what my data storage story is. It's really difficult right now. There's a million different ways to do it. There's the relational, no SQL. I want to not kind of have to care.
Right now, I don't have to care about where my frontend goes. It just goes to CDN, done. Then my business logic, I'm like "Well, if we can get the Lambda Story, figured out," and the restrictions become fewer and someone is going to orchestrate it for me. There's like, "Boom, Lambda's everywhere," right?
Tom: They become super cheap. I could have a globally distributed, fully-edge web app in a couple of minutes, and it doesn't cost me very much.
Tom: In five years, we can totally be there. Then even longer than that, is what I call a universal deployment machine, which does everything, including data and you're just like, "I want to read data and write data, and you figure it out. You make indexes for me. You make it fast. I just want data."
What's the CDN of easiness? How easy CDN is for getting your frontend out? What is that for data? I don't know, but that's what I want to see in 10 years.
Chantastic: I love that. I feel like you have all of the pieces in your experience from doing so much with Rails, with GitHub, to Jekyll, to TOML, which [laughs] seems to be a really important piece of controlling your infrastructure and whatnot.
I'm just so excited to see you leading this charge and having the vision and sharing it through Redwood. If people do want to get involved in the community to learn more and share their first-learner experiences, how do they start doing that? How they get involved?
Tom: Come to redwoodjs.com. There is links there to our Discourse forum and our Discord chat server. Depending on what you're doing, you can engage in either of those ways where RedwoodJS on Twitter. If you want a free sticker, we will send you three...
Tom: ...free stickers literally anywhere in the world, as long as you have an address. We will send it to you completely for free. Go to redwoodjs.com/stickers and fill out that form right there, and I will send you three Redwood stickers and put on your laptop, and then you're a bona fide member of the community.
Tom: We love for anyone to be there, builders, distributers, people noodling around, people that are early in their careers, people that have been doing this for decades, everyone. We want everyone there. We want to help people build valuable stuff for the world.
Chantastic: I'm super excited to see how this project takes off. How can people find you about the Internet and see as you continue to develop Redwood?
Tom: My handle is @mojombo on Twitter, and you can search for me on Internet. You will find me in the various places and how to email me, so I'm easy to find, @redwoodjs on Twitter give us a follow. Give us a star on GitHub. That helps us a lot. If you wanna see GitHub become more used and continue development, a star on GitHub is really valuable.
It's a signal for others that there is interest there and that is going to be a long-lived products so, that's how you find us.
Chantastic: Awesome, Tom. Thank you so much for your abundance of time with us today. I really appreciate you taking the time to explain so much of this to me and our listeners. I hope a lot of them join in and get excited about what you're doing. Thanks again for taking time to chat with us today.
Tom: Absolutely, it's my pleasure and very happy to be here.