my tech stack is something that's very important to me you've been around for a while you probably remember the early days this whole Channel started around the T3 stack before T3 was even me it was my stack I did have the domain t3g way before any of that was even thought of before Tailwind was even created because T3 stands for me it's three letters after the T but a lot of things have changed since I put out the original T3 stack I've looked at a ton of different solutions and changed a bunch of stuff in my stack but also went back to a handful of the things I loved back then I haven't done a proper update on what my stack looks like since back at the start of 2023 I did actually film a video about this last year but it kept getting pushed back on the calendar until it got so out a date that I feel bad putting it out now so instead I'm going to break down what I'm using now and more importantly why I wouldn't recommend a handful of the things I am using to anyone who doesn't want to go insane in the process of building my Stack's a little chaotic now but more than ever I think there's a lot we can learn from it in order to build good production ready type safe typescript applications but I need to pay some bills in order to keep these things maintained so let's hear a quicker from today's sponsor before we dive in my teams are shipping more polar requests than they ever have before probably because of all these nice AI tools that said it also means they're waiting on CI more than ever and I'm tired of it what if I told you there was a way to make your CI two times faster with just one line of code changed I would sound insane which I understand but hear me out because blacksmith is killing it it's literally on line change in your action Runner and now you're getting way faster builds and way way way better Better Price there's tons of companies already using blacksmith for their production builds including companies like Clerk and they've done crazy stuff to make their builds so fast one of the fun hacks is using gaming CPUs like in gaming computers because they have much higher single thread performance which is super handy when you're trying to do a big build with lots of single-threaded work they also have much faster caching because they locate their cash directly next to the CI boxes which is silly that GitHub doesn't do it but it helps them a ton also helps that they give you 25 gigs of cash instead of the US ual 10 gigs you get from GitHub oh if you're curious how fast that speed Improvement is it's from 100 megabits per second to over 400 they've already built Runners for pretty much every language you could want go rails rust python JavaScript whatever you're almost certainly covered oh and by the way 3,000 free minutes a month you don't even need to add a credit card it couldn't be easier to sign up and give a go thank you blacksmith for sponsoring today's video check them out today at so of.ink blacksmith I have the two applications up here that are the ones I've made decisions about the most recently there's a lot of overlap between the two but also a lot of differences and the one that is older has a stack I'm happier with but also doesn't solve some specific problems that the stack for the other solves so these are pick thing and T3 chat if we go through and break this down the traditional way there's a handful of categories that most of us care about there's front end framework style System state manager API system Library backend framework backend language database what I want to call the like dialect I guess database dialect database provider hosting provider Etc there's a lot of these categories and if you've been around long enough you can guess for most of these what I'm doing react Tailwind Chad CN State Management is a more complex thing API system Library also more complex thing backend framework next usually backend language type script database dialect we'll get there database provider we will very much get there and hosting provider versel Cloud flare NFI so this is the The quick summary but the details are about to get a hell of a lot more chaotic I also missed pieces in here like uh router I'm sure we'll find others as I go off is a really good one thank you chat package manager there are a lot of pieces to a modern front end stack and copy pasting the ones I pi is not going to be the right solution and there's a handful of things you might not need at all like you might be building something that doesn't need an off provider you might be building something that the database is just your off provider you might be building something where you don't need a state manager you can just do it in vanilla react or with server components there's a lot of different things you may or may not need throughout all of this which is why my community originally built create T3 app because people wanted me to put up a template of all of the things I like to use and how I use them but but if I did that you'd be installing things you don't need in tools that you aren't using so I suggested that someday if I had the time I would build a CLI to scaffold out a xjs app the way I would recommend and then just didn't but then Nexel for my community did and then CJ and Julius stepped up to help maintain it I've contributed zero code to this project but it is awesome and it still is how I start most of my nextjs applications when I'm not doing like a quick demo of a next feature creat T3 app has you pick each of the parts when you set it up so if I make a new project sandbox pnpm create T3 app at latest and you do this you give it a name some demo you pick between typescript and JavaScript and only one of the answers is actually valid you say yes or no for Tailwind you say yes or no for trpc which is a very important piece we'll get to in a bit say yes or no for next doth there's still a future where we add other options here CU next oth is in a weird State then for the database RM your options are none Prisma or drizzle you can use app router if you want I would highly recommend it nowadays and then you pick which SQL dialect you want hopefully by now you're starting to get the idea it does all of this stuff for you but it's still the modular pieces we're not forcing all of them on you we're giving you options and you can swap out one option for another if you would like which I think is the whole point of the stack that's why I built it Simplicity modularity and full stack type safety I didn't make the template here but I did make up the stack and I did really push for this modularity at a point where as an industry we were starting to go in this way but the the Mind share was still leaning towards the rails way of building things where everything was provided as one solution that was part of the framework I wanted to have the best solution for my different problems and the ability to throw away the parts I don't want and this stack helped me get there in ways I didn't realize were possible at the time and it's surprisingly close to the stack that I ship nowadays as you'll see as we go through the parts so let's do that let's go through those parts I'm going to start with pick thing because at the very least the like core app part is relatively similar to what people probably should use I'm very happy with the stack here overall and I even had Ben Davis my channel manager and also fellow YouTuber who's more a spelt guy helping with this code base and he's had such a good time with the way this project is set up that he's trying to copy parts of it into the felt ecosystem and he's having a hell of a time doing it so you could just look at my dependencies here and get a lot of information about what we're doing you'll probably get most of what you need from seeing that but the way we use these things is interesting enough that I hope you stick through as we do it all the probably best starting point is right at the top here the front end framework it is very rare I build something nowadays that isn't using react I say even though I just shipped one of my biggest non-react projects ever needless to say a project like where is it here unduck probably probably isn't the best representation of how I like to build cuz this is meant to be very minimal a package Json as you see is loaded with dependencies we have the whole Vite plugin pwa which actually by the way is a Dev dep I just need to move it over I'm lazy I'm sure there's five PRS that do it but there are three build plugins oh no so complex if we look at the code you'll see oh wow it's even more complex it's basically vanilla typescript and the HTML is written by this one inline function if you don't pass search prams there is no front-end library for this project this is a very quickly thrown together HTML snippet in JavaScript that is a very specific thing so when a project doesn't need a complex UI or all these Cool Tools and solutions I'm more than happy to throw away all of them so my reaching for react isn't because I think everything should be react or I'm too lazy to build my own uis or whatever it's CU complex uis benefit from a library for building complex uis and For Better or Worse most of the UI Bill nowadays is somewhat complex so something like unduck which is very complex as you could see doesn't need a library but something like pck thing which is inherently significantly more complex you'll see this benefits a lot from a library that lets us have more Dynamic Behavior in the application so let's talk about how we actually build those Dynamic behaviors and all of the layers for it let's start at the root layout the first thing you'll see in most of my apps that have off is clerk I still find them to be the easiest way to add off to a nextjs application and have all the niceties like the little button you can use for signing in actual place to store user data not having it clog up your whole database not having a thing you have to deal with and maintain not having to go set everything up with all the different off providers you want to add it's way easier to get started and if the app does get far enough that I want to release it to the public it's relatively easy for me to push over that hump but there are times where clerk doesn't make sense which we'll get to in a bit because I have not been using clerk in some of my projects and on one hand it's been very nice and on the other hand it's been very painful for the most part Clerk's been really nice and when I don't have it I do very much Miss it I didn't have my analytics which uh what did I even use for analy for this project oh this is the versel analytics component I don't remember putting that in I have no idea how that ended up oh versel analytics for now from me 6 months ago that's how that got there getting owned by the git T plugin once again I normally have it uninstalled and I will probably do that after this or G lens whatever it's called yeah but then we have the analytics that I actually care about which is post hog generally speaking if you want to know how much I care about one of the projects I built check if I have post hog set up if I have post hog set up I probably care about the project if I don't have post hog set up I probably don't care about the project post hog is a phenomenal analytics provider that I've loved working with I bullied them into sponsoring me as their first ever sponsored thing because I don't want to talk about other analytics providers I don't like them much I really like post hog so I use them for everything this isn't an ad they're not paying for this they might ask to be an ad for the video but I will reject because this is just my actual take I've been using post hog for years before they sponsored me and I'll be using them for years after I like them a lot it's a really good way to do analytics for your product everything I care about is using post hog things that I want basic numbers on and don't care at all about might use plausible but I've been moving more and more away from plausible in favor of post hog because I need data that is user specific plausible is very much Anonymous generic web tracking analytics but it doesn't have product analytics which is a different thing I should do a whole video about this in the future but web page view analytics are very different from product analytics it's nice to know which Pages people are going to but it's much nicer to know how many image uploads a given user does and those are entirely different products the first is a Google analytics thing like the Google generic analytics product post hog is more like things like mix panel or amplitude where you can do the Deep product analytics for the things users are actually doing and if you want to know how many users have uploaded more than 50 images that is not a thing you're ever going to get out of Google analytics are plausible and more and more my applications are actually user specific so I need more things for that but also I have stuff like QuickPic which is my service for quickly formatting images in quickpi I think I have plausible setup on it I vaguely remember doing that this is an in browser app that I've barely maintained since launching it that is a nice quick way to solve a handful of image management problems that were pissing me off at the time quick pick is not a real service that I'm maintaining it's a quick picture management tool that I built to solve some specific problems pick things an actual Production service that we shipped for managing your assets as a content creator I still use Quick Pick for a bunch of stuff yes for those who are asking I love Quick Pick I use it all the time but pick thing is crucial to how I run my business every single thumbnail I make that has me in it is using one of the assets from quickpi anyways from here we see the thing that I didn't have originally that I ended up adding later on made my life much better trpc I keep making the same mistake where I con myself that my Dynamic applications can get by with server components and they cannot I wish I didn't need TPC all the time I wish that the apps I was building were simple enough that I didn't need it and sometimes they are if I hop to marker thing for example which is another one of those projects I use a lot marker thing is how I manage all of the markers for my streams which is how I take my 8 hour stream and chop it into individual topics so that my team can start editing it without having to download the whole thing and chop themselves what makes marker thing fun is it doesn't have a database and its actual data access layer is kind of hilariously simple if we hop over to the code for this and we go to a channel page here's the code I run it on the edge because at the time that mattered this is pretty old I force Dynamic to make sure that the page was Dynamic every time you'd go to it thankfully most of these are solved with the new Dynamic IO stuff but where things would get fun is I could just Mount this async component that would grab your off information would grab the twitch credentials using that off information would grab the twitch user ID and then fire API calls in order to generate that page with all the right fods super cool and none of this requires a database at all the entire product of marker thing has no database I am just getting the data from twitch using the credentials I got from clerk it's awesome and it made this code base significantly simpler funny enough I had built this project twice before and I wanted something that I was more confident sharing with other people so I sat down with Mark and we quickly rebuilt it it took like a day and a half we built something significantly more maintainable and significantly less painful and we did that by throwing away all the parts we didn't need it's still kind of crazy that a service I use every day that it's relatively data heavy grabbing all the things that I need for all my videos that this service has no databas is something I find really genuinely cool I love what we built with this tool and I love how the react patterns have worked for it you can also see how old it is here this is a 2-year-old code base God that hurts I'm getting old so fast when server components first happened jsx didn't support asynchronous function calls so you had to put a TS expect error before calling an asynchronous component that's how you know how old this code base is which is adorable painful but adorable yeah so this was all in on server component we got a lot of benefit from it like the behaviors here aren't Dynamic once the stream is done the stream is done this content is static at that point so you don't need a lot of back and forth between the client and the server so not having good ways to go back up to the server didn't really cost me anything this is actually one of the simplest code bases I have and if you don't believe me it's open source you can go take a look I love this project I think it's a great example of keeping things simple when you can and taking advantage of a service like a clerk to not have to put a whole bunch of work into parts that you shouldn't have to my previous attempts to do this in rolling my own off handling twitch o off myself properly storing all of the stuff in database and managing all of it between the new version is comically simpler whole thing is 1,200 lines of code and most of that is like just reformatting data from the Twitch API and a giant pile of types for said data from the Twitch API I loved that so keep things simple when you can if we were to like diagram out my my stacks by complexity the simplest is unduck because unduck has no dependencies it's as simple as can be then marker thing much more complex but not actually complex it's more complex than undu we have to handle off and things but I managed to trim down the layers there to make something way more maintainable and I didn't get there by the way by thinking it through and just magically coming up with the simplest solution I had to write it more complex three times and just trim the fat until I had something simple and maintainable then we have pick thing which funny enough I went through the same thing with I rewrote pck thing probably four times just cuz I built it to use had a problem with it looked at the code base like I don't want to touch this and just rewrote it and did that a few times and then the version that we shipped is our production version it's comically better for reasons that I'm not going to share too much of because that's valuable enough information I it's niche enough and valuable enough I'm not giving it away but then we have something like T3 chat significantly more complex like there is a big complexity Gap here simply because marker thing isn't interactive and unduck has no server at all so there's a slight gap between marker thing and unduck then a big gap because pick thing is now an interactive service with actual like user information and data that I have to manage properly permissions Payment Systems so many other things then T3 chat arguably pretty big gap here because now I have to do things very performant shifting data between tons of different apis and services and mangling it all on the client but then there's another gap before upload thing upload thing is not a code base I'm comfortable enough with right now to confidently share how it works because Julius and Mark have fully taken it over because it has to be more complex and I would not be good at my job if I understood how upload thing worked fully at this point I'll be real so yeah we've covered the Simplicity of unduck and marker thing at this point I would say reasonably well let's go back to pick thing because I think it has a lot of interesting stuff we can learn from we go to dashboard app page here is the page you get if you're going to slapp and SL apppp is the page on pick thing that has your information the things that you've uploaded so if you're not signed in then I redirect you to/ login I then grab the subscription from database if you're not subscribed then I return the checkout component instead but if you are signed in and subbed you just go straight to image page and here I originally did a server component I have since changed my ways is now a client component I get the data from react query well from trpc using react query we'll see a big change to how this works when we go more through the T three chat code base this call might be weird because I'm making a use Query call but I'm not putting something on the other side this is me prefetching so that I don't have to fetch this stuff later and have another pop in so by doing this here I able to skip multiple steps and fire a lot of data fetching with a single batch which is really nice then if you don't have any images I give you the little info drag and drop images onto the page to get started otherwise you get the actual content you go to grouped image grid takes in the images grabs the tag prams and it renders the image groups nothing too complex here the closest thing to complexity in this code base at this point is probably the database and the stripe Integrations in particular if I was to really go back to this code base and make it more maintainable the first thing I would do is gut the stripe implementation and subscriptions cuz we were we were confident that modeling that data properly was still the right thing to do and I've since learned the error in those ways that project was when I realized I wanted a better way to do stripe and then T3 chat was when I finally raged and did it if you're adding payments to your app please read this I have been through so much hell with stripe and almost everyone I've talked to that thinks that their stripe solution is working and good once I force them to sit down and read this their conclusion was oh yeah I missed a lot of things at this point I still recommend stripe over Alternatives none of them are far along enough that I'm confident in them but doing Stripe Right isn't easy the core piece that I recommend is syncing Stripes data to a KV of some form not to a relational database adding that level of complexity to your main DB just throw it in a stupid key value star and use that as the thing that you check a user's status with makes life significant L easier maintaining complex Payment Systems highly recommend copying this I wish I did for this code base but the rest is pretty simple you might notice something interesting here sqlite this project was originally on the free tier of Planet scale you've been around for long enough you might remember back in the day Planet scale had a pretty generous free tier where you'd get their $30 a month tier for free for one database they changed that because the free tier was costing them a ton ofy and the people who were using it were just support problems they weren't actually meaningfully benefiting them and they wanted to focus more on databases that cost $6,000 a month not ones that cost $20 a month so they killed the free tier it have been scaling up to be used by Massive companies like intercom like Square for cash app sorry block for cash app and really big scalable ones like T3 chat we'll get to that all in a bit but I had a handful of these smaller services that were using Planet scale where I just couldn't just ify the cost because they weren't making much money so out of curiosity and willingness to try something else I gave terso a shot for this project and I was initially quite impressed and then I watched the chaos of turo as it slowly unfolded there's a reason I don't talk about terso a whole lot and I don't recommend them very often it's one of those products I wanted to see succeed and I am losing confidence in every day they're a weird group and we already see people in chat bringing it up my data got deleted I have watched some of the most embarrassing outages of my career from turo in case you're not familiar turo Tech their main concept was a distributed sqlite database for whatever you want to build and they' have gotten lost multiple times throughout the process they focus way too hard on edge and moved away from it the thing they do really cool is pricing it's super cheap to get started it's relatively cheap to keep using five bucks a month for databases is really cool problem is you don't know if the database is going to be there tomorrow or if you'll even get the right database back there was an incident a while back where a person was trying to query data from their torso database and nothing came back and they were confused so they went and open up the inspector and they had access to somebody else's database that had credit card numbers in it because the way torso's info worked at the time was if you're on the free tier there wasn't compute being left up instead they would store your database in S3 and pull it back up when the request was made and they had an error in their code where they would pull up somebody else's S3 backup instead of yours sometimes which is one of the most horrifying things I've ever heard about a database ever yeah and recently they started moving over to AWS I believe they were on fly iio at the time they're starting to move to AWS and they accidentally wiped all AWS users databases recently so if you want your database to actually keep your data be cautious I hate talking about these things I hate dunking on the ter guys but they've been weird enough to interact with that my confidence on this product is relatively low great quote from chat is torso another example of don't gamble on the database yes I gambled on it and I'm lucky I haven't had the massive issues I've seen others having yet keyword yet but I'm I'm not risking it at this point I'm not taking the chance so when I first started T3 chat I went a very different path T3 chat started entirely with redus the only dat datase for T3 chat for a while was redus and that was actually really nice until people started storing hundreds of megabytes of data for their crazy threads then we end up with the Divergence that exists between pick thing and T3 chat which is T3 chat started with KV using redus on upstat specifically which was actually awesome up stash was super nice to work with super cheap scaled great the amount of storage per user was getting to a point that was untenable so we moved over to Planet scale and it's been super smooth sailing since when a service gets to the point where I need the benefits of the scale and functionality that planet scale provides I make the move then I've been very happy with Planet scale for all of the Production Services that we run that have crazy throughput things like upload thing and more importantly things now like D3 chat both benefit greatly from the crazy performance characteristics and scalability of Planet scale super reliable super good super happy I don't want to call out other Solutions I will say that I have played with almost all of them and I am happy with almost none of them the the two that currently sponsor my videos are actually within the better options the Prisma postgress product is probably the way I would recommend doing postgress right now I haven't deployed it yet but everything I've seen in the demos I've played with from it is really good and pris knows databases so if you want if you really want postgress like really really want postgress probably the direction I would go for it personally but I personally just don't use postgress nowadays almost ever the other option that sponsors honestly I have regret not using convex more these guys are killing it I put together some demos of like parts of T3 chat using convex instead there are quirks and gotas cuz the big thing with convex is they run your compute your apis don't run on your infra anymore they run on theirs but by owning that they allow for really cool characteristics with your queries and mutations where everything that could possibly update your database exists in their layer so if some mutate something that somebody else has queried for it can live update which is super super cool I've been really impressed with convex and if they can figure out their local sync and caching story a bit further I would see a future where we actually move T3 chat to convex enough parts are missing for that chaotic local layer that I just deal with the sink layer I built myself still but convex is like the thing that I look at and yearn for the most and and I will once again emphasize from chat that a lot of things have come up that I don't recommend I don't want to spend a lot of time dunking on other Solutions but if you're watching this video you're probably thinking but what about X I've thought about X I've probably even shipped something with X and I did not like it so take that as you will I could be wrong but I've been very sad to see the terrible scaling characteristics weird performance characteristics and overall unreliable experience of pretty much every other database people are mentioning in chat including ones I've been sponsored by you might have noticed a theme starting to form here hopefully this will help emphasize the core of how I think about my stack step one start with the simplest reasonable thing step two add complexity as it's necessary and step three regularly reflect on that complexity to see if it's actually necessary be very willing to delete and circumvent complexity where it is possible to go back to like the marker thing example I was convinced that I had to store a lot of data in DV for that product to work and as I thought about it more and more and kept dealing with edge cases I realized oh I'm effectively just transforming the shape of data that already exists in the Twitch API can I just use that the answer was yes and it makes things a lot simpler so that's what I've been doing with everything I can generally speaking complexity is the enemy of success in scale and all these other things the only thing that actually scales is simplicity so I always strive for it and you'll notice in my stuff that I often find sometimes crazy hacks in order to maintain Simplicity to the best of my ability I also can't help but call this out I saw people mentioning Google Sheets as a database as a way of keeping it simple it is not believe me I want to use Google Sheets a database so often I genuinely desperately want to good luck getting that off the problem with Google Sheets the database is it oh it doesn't scale it's Google Sheets Google Sheets scales really well good luck connecting to it via their API the API for Google Sheets is such trash it's such a dumpster fire it feels like it was written in the 90s I don't know how anyone does anything with the sheets API just getting approved through Google's Cloud stuff to be able to authenticate a user to access Google Sheets in the first place or to hardcode one sheet you've set up on your side I actually want to use Google Sheets as a database genuinely it is effectively impossible funny enough I was actually working on a project with Will Osman recently because he wants to build a hiring board and I wanted a simple database that he would be able to edit without having to build all the UI stuff for it so I started with Google Sheets 2 hours into trying to get it to off my roommate in CTO Mark comes over and laughs at me and says I warned you Theo don't do this so I caved and moved to notion which has actually been really nice the notion API is totally fine so yeah Google Sheets isn't the simple option and that's not because Google Sheets isn't simple that's because the API layer to actually do anything with it is one of the most unnecessarily complex piles of I've ever tried waiting through in the last like at the very least last five plus years don't use Google Sheets as a database not because it's terrible to use a spreadsheet product as a database but because the API to access that one is particularly trash it is not the simple solution and I wish it was I do genuinely wish it was it's just not not viable anyways start with the simple thing add complexity as it is necessary and regularly reflect to see if that complexity was necessary in the first place constantly take the opportunity to reflect on the problems you're having the edges you're running into and if you find like enough bugs in a given thing that you produced building the intuition for when it's better to try to circumvent that solution entirely rather than patch is a skill you have to hone over the years I don't have any advice other than try both when it feels right and shift around over time but the the gap between patching versus replacing is a really hard thing to strike the right balance for and in an error with a I where replacing is easier than ever I'm scared we're going to overcorrect and become much more replacing much less patching but right now we're much too willing to patch something that's fundamentally broken and not willing enough to replace it when it makes sense to so I'm okay with this correction it's been a nice change in the industry to see us more willing to delete things that don't work like with T3 chat you might have seen my video about the crazy journey I went through with the database there I deleted more code than I shipped there I've deleted three full sync and and data layers that I built for T3 chat because it was easier to rethink it from the ground up than it was to patch it at least patch it the number of times we had to oh I like this framing a lot I like this a lot overnight send if you're not adding things back you've not removed enough Banger love this so where were we now this this has been a chaotic Journey let's see if we can get more value out of it ooh State manager obviously style system tail and chaden watch my video about modern style Solutions if you want my thoughts on that a deeper topic State Management is a complex one I'm just going to list a bunch of things and hopefully not have to talk too much about them just some things that are useful react query server components Jodi zustand Legend State dexi these may or may not be placed in the order that I recommend trying them and when the solution you're on stop serving the need that you have you move down one layer I would never make a claim that bold though because why would I ever pretend to have used every single modern State solution and only recommend six of them and then use four to six of them in parallel at any given time I'm not saying always use react query but I'm kind of saying always use react query at the very least I'm saying that every time I didn't include react query I ended up regretting it at some point so yeah I see a good suggestion from chat which is I start with server components first react query second usually I do the same but almost every time I end up having problems that react query solves better but yeah I I really like server components and RSC behaviors in the minimal case I would go as far as to say if you can use server components for the core of your application without doing anything too scary you almost certainly should like when I built my pager app which uh you guys ever wondered how we get the new models added to T3 chat immediately it's cuz I built an app to page me and the page me app allows for people who are approved of the custom password and off to tell me a new model just dropped and then I get a phone call that alerts me so I know that that happened the page Theo app was originally generated I tried lovable it struggled with some of the more nuanced things I tried VZ and it almost scaffolded it right I got frustrated and just went and built it myself instead and by myself I mean with a lot of help from our friends over at Claude and Cur you get the idea though the fun with this one is that I did everything through server components and it was actually quite nice I do have a KV because the KV stores all of the models that people have submitted so I have that little section that shows if the model has been submitted or not so I don't have five people paging me for the same thing but all of this is server components there is basically zero client code on this project and it's been very nice because I'm basically just using react to build an interface to my KV and an interface to my free tier what's it called twilio for the phone calls side so it's actually beautifully simple and I love it because this doesn't need a bunch of complex client side behaviors it needs a basic form with basic submission behaviors and an off check and a way to list the things that people have submitted when you use server components in a simple way they are incredibly simple the problem is if you use server components for complex things you'll quickly probably at least run into some insane problems I still like them a lot I miss server components in all the places I can't use them I've missed them a lot throughout T3 chat they're not using them at all if you can't use them react query really good way to deal with async stuff in react react sucks at async react query makes it suck less Jodi is the oh I need this local storage value in five places is what I almost always use it for zustand is oh these five things relate to each other and I want to organize them all in one place I use zustand primarily for stuff like Ping where you have the really complex like interactions between users device State Management and all the other things for a live video call Z stands killer for that use case Legend state is a phenomenally fascinating project that came kind of out of the react native world that is a super granular really well optimized State solution with good sync Primitives built in still very early but I've been playing with it more and more considering moving some stuff over to in the near future and then dexi dexi was built to make it so that Internet Explorer 7 could actually use an index DB like like thing indexdb is a terrible API that is really hard to use dexi is currently the core powering most of T3 chat it has been awesome their Cloud product scares me and doesn't really solve the problems that we have but the core dexi library is probably the best way to deal with and fight all of the chaos that is indexdb and browser standards about storing data is what we're using for T3 chat I wouldn't recommend it unless you need it but if you need it it's very easy to recommend if you're storing more than 10 megabytes of data on the client you probably need dexi for it that's where I'm at with State managers start simple add complexity as you need it and trim constantly or you will slowly go insane okay API system in library almost all of the projects I've talked about so far the big to being pick thing and T3 chat started without trpc when I built them initially and ended up with me adding trpc because I up and deeply regretted not having it trpc is still the only sane way to deal with complex backend front-end relationships and the results are incredible it's so nice to work with so this is the switch that manages whether or not the database gets updated with your chat history if you do or don't want to sync your chat history if I go to my use sync enabled hook you'll see something interesting here use Query trpc wait don't you call trpc do usequery what's going on there what's going on here is there's a new way to call react query with trpc where instead of trpc wrapping react query we take the things that react query expects the keys the options all the other pieces and we generate it and pass it to react query so we can use the same react query instance for all of the things in our app and it's really really nice I've been super happy with the experience using this new way it's weird cuz now we're interfacing between react query and trpc back and forth more often but we get a lot of cool benefits from it too it's been really nice the magic of trpc is the type SA and simplicity of things once is set up but the magic of How Deeply this type safet is integrated this component is a client component I might not have put used client on top but every component in T3 chat is a client component due to the way we architected it we'll get to that in a bit but watch what happens when I command click get preferences now I'm in my backend trpc folder on the exact function that I am calling on the client how cool is that it's so so nice hopping between the back end and the front end with typescript is The Binding between the two no graph schema interpolating no crazy open API spec that no one remembers to generate that makes it impossible to figure out what's coming from where and everyone's scared to change you just go to the back end and make a change and the front end will see the change it's so nice and every time I don't do it I end up regretting it I went super hard with server actions with the first version of T3 chat and we have since gutted all of them I probably should have started with trpc but once again as I always do I convin myself oh I don't need it this is simple enough and then as soon as it's not simple enough I desperately reach for Julius to hop in the codebase and set it up for me yeah trpc still feels borderline necessary for complex enough applications if you could possibly keep your back end and front end in the same project trpc is going to make your life much easier and allow you to stay in that mono repo monolithic solution for a while it's really nice I'm really happy with it and unlike server actions it's also relatively stable and doesn't have a bunch of weird edge cases that make no sense at all I've been to Helen Back I have a lot of stories to tell at some point speaking of stories to tell let's dive into how I have the routing architected here we're going to skip a few steps here but the routing we have set up is fascinating you'll notice that despite being a nextjs code base we have react router in here I really didn't want to do routing on the server side I did not want using T3 chat to ever block on server ever I wanted you to be able to navigate and do things in T3 chat without ever having to deal with the network connection blocking you from going from one place to another so I use react router in nextjs how did I do that a pile of hacks I don't necessarily recommend I am still in the process of exploring what we've been calling the nexit for this project to see what moving off next looks like and every time we make meaningful progress in it something stupid happens that requires us to rewrite way too much in a way that is less maintainable and more complex and I sigh and shrug and just stick with next I have been very surprised how well this hack has scaled for us but I am not recommending it I do have this though here I import next dynamic because I can't SSR this component if I do everything breaks Dynamic is for static because I want this route to be static and then I export the function app and app is a much more traditional react router client side application why is this in static app shell why isn't this just a catchall route because in nextjs catchall routes are always dynamic because it needs to know the URL which means that I was running server code every time you navigated to the first page when you open T3 chat that was bad and dumb so I fixed that here by making everything static and making it a static route because if I made this a catchall route it would no longer be static and this would just error but how does this handle every page more hacks here's the app shell rewrite if the source is slash path which means if it's anything then I redirect it to static app shell but I also added this missing call out here because the trpc end points also use a catch all route and a really fun thing about the way next works is if you do a rewrite in the config here that takes precedence over rewrites and catchall routes in your actual next router so this router was having its routes intercepted by my config and when you would try to call trpc it would get back that static HTML page so I had to add a custom header on all trpc calls and then filter out things with that header in my next config to make sure that they don't get abducted by this catchall route I am not interested in Sharing how long it took me to get this all working properly I just hope I can save some somebody who's making the same bad decisions as me a little bit of time in the process could I use tan stack router could I use remix could I use all these other things I'm going to show you guys something fun notice this PR here notice who made this PR here notice that it was done last month and it still hasn't merged I have been promised by a lot of people smarter than me that this move would be totally doable and easy those people are currently making changes to their Library so this is actually somewhat possible at this point it's a race between the remix team and the T stack team as to who can add the missing pieces first so I can make a move that doesn't make me rip my hair out the way that remix and react router handles cookies feels like we're in the '90s again and tan stack despite being way further along with those things has enough pieces that don't fit together nicely for our use cases that Tanner is going really hard on single Peach app behaviors in order to make it way better for us to adopt they're also in the process of removing viny which is the core that they've built around for a while and I do not want to adopt op a framework that is about to rip its core out so one of these might be the move in the future but as crazy as it might sound that I'm saying this next is more stable than the other options right now even in my weird bastardized way of using it so yeah stop asking about other Frameworks I've considered them more deeply Than You by people who are smarter than you people who are smarter than me and we'll do it eventually but for now this is working really well but once again the point of this video isn't you should copy my exact stack it is a a set of warnings on the sirens that will call you on the process of trying to build things like this yeah good luck have fun so that's the routing situation and also the fun workarounds that I've learned to deal with since to make this all viable what else do we have that's valuable in the stack okay we've handled the State Management API stuff handled backed framework still on next will'll be there indefinitely I wish I could use Elixir more but typescript is just too useful for too many different things we covered the database dialect and provider my hot take there is use a good KV for as long as it's reasonable because any data base can be turned into a DB but not every DB can be turned into a KV so if you start with the key Value Store moving from the key value store to SQL is not particularly hard and you can do that at almost any point and be fine that's what I did twice and it's been totally sustainable for us since I started and I also really like the experience I've had with up stash they've just been great really easy way to deal with data at scale for things that need to respond really quick I've been happy with it highly recommend use it when you can move off it when you can't keep it simple we just covered the router next when server react router when client I used to be a really really big fan of wowder which was a really minimal react router alternative react router is in a pretty good State now hand router is in a phenomenal State now I need to use it for more stuff I just haven't I haven't had complex enough search RS to really benefit from it and I don't want the data loading patterns unless I have the server side part with tanack start so for me tanack router is is just waiting for the tanc start part to boldly come together and they'll probably be all in on it but for now this is stuff that I'm using to keep my stable the funniest part with the way we're using react router I probably should have mentioned this before this is not the new react router syntax I'm using the react router syntax from V4 they're on V7 this is the same router syntax I used at Twitch in 2018 the new stuff seems really cool the file based routing and stuff is genuinely seemingly pretty awesome I'll get there when I get there not my problem right now we got to do I'm very happy with my routes being components that have a URL and the thing they render pretty simple makes my life better I'm happy with this everybody saying I obsessively adopt the newest things have not read any of my code I don't I say right before the off section because the two off providers I find myself using the most are clerk almost always and if not clerk pain I have a long video about the different off options and when I do and don't recommend them I'm also getting more and more work OSS pelled as I see the benefits for the Enterprise side like if you want to be able to get a Enterprise team to set up your crazy off stuff in their company through their it team the admin panel is just one of those things that I never want to do in my life like if a different if a random company that wants to buy T3 chat needs to set up OCTA or samel I don't want to do any of that and work OS is what we'll almost certainly move to when the time comes for Enterprises to start adopting my tools so clerk if you can you have specific needs I personally am pretty happy with openo openo is built by Dax and crew over at SST it is very Hands-On it does very basic stuff for you and shows you roughly how to pull it all together it lets you separate your o into its own service and I I don't want Au in my database ever again my database is for my data not for my off keep my off out I am very blackpilled now on user table not being in my database and it's made my life significantly better open off lets me do that trivially where I our off layer for T3 chat is a 20 line of code worker running on cloudflare writing KV data straight to the cloud Flare's worker KV and I don't touch it I don't interface with it I don't do anything with it I just call it using the open off client and I'm done it's really nice it is like roll your own minimal featuress Clerk and I've been very happy using it for T3 chat even if it took me forever to set up and we have random weird edge cases because the examples they gave were missing things that I have to go polyfill after validation is a a bunch of other random things suck about it but that's welcome to Rolling your own off it is what it is but I've been happy with it it's fine I did not want an off solution that expected to run between every single request because I wanted an off solution that wouldn't block me for local first stuff and with T3 chat I wanted to minimize the things between the user and the stuff they're trying to do and Clark makes life much easier by being in your nextjs middleware and running between every single request I had zero interest in an off layer that ran between requests I wanted an off layer that I could call when I needed to for things that I wanted to check and that's it I wanted the simplest possible off layer that would not block requests until I chose to and it was flexible enough to get me using it and I was happy overall what I recommend this over clerk if you can use clerk I would probably recommend just using it but if you have specific needs performance characteristics desires and other chaotic you're trying to do open off lets me keep my separation that I really like to keep I've been quite happy overall you want my thoughts on all the other off libraries that are consistently coming up in chat if only I had a video where I broke down every single current o solution and how I feel about it that' be really convenient Wouldn't It Anyways that's where I'm at with o oh package manager finally an easy one I just use pnpm bun will get there someday I want a solution that just does the one thing though and pnpm has made my life much better having everything cash locally and for the most part behaving properly monor repos bun is a runtime bun is also a package manager but their focus is on a lot of other things bundling runtimes lots of other it's missing a ton of stuff for monor repo management and every time we try to use it in monor repo we end up in hell and back on pnpm there's a future where I start using bunm more but for now pmpm has made my life significantly easier I really hope you guys aren't sincerely asking what runtime my runtime is noed my runtime will stay noed my runtime has been noed for a long time and it will be for a long time I use cloud flare for a handful of very specific things that make sense like an O wrapper that's on top of a KV or for p thing all of the image optimization is calling different services like when I generate the background removed version of this image that's using a handful of different AI companies providers and apis to remove the background and generate a new asset I do all of that through Cloud flare because I after again remember I rebuilt this so many times I had a really clever solution to the issues I was having with all the state management and keeping track of what had had the background moves and whatnot look at the URL it's kind of nonsense so I'll open up my editor bg. image. engineering what's image. engineering oh I guess there's nothing to see here never mind I'll finish image engineering at some point but what this project actually is is a CDN and image optimization layer that I built on top of cloudflare because it's runtime characteristics were very convenient for the type of scale and weird waiting behaviors that I wanted to have so that a user could request an image that doesn't exist yet and I could hold the request hostage until the thing existed it was a very very nice way of removing all of the state and that's probably another one of the themes you should get from the my way of building whenever I find a way to remove state or remove split brain where data exists in two places I will go to the ends of the Earth to make it happen I will do really stupid things to make it so data exists in one place instead of two the less I have to mirror and change and modify and derive data in different places in ways that it can fall out a sync the happier I am and every time I have data in two places I have four problems at least every additional place that your data exists is an exponential increase in the surface area for potential problems and The more I've been able to single source of Truth things the better life has been and I am far from the only one saying this and this is far from the only industry that's realizing this funny enough I just hung out with Luke from LT last night and he couldn't stop talking about how they're rethinking things internally to have a single source of Truth for stuff because having multiple people multiple to-do lists in different programs and different calendars and all of that is burning the company Down single source of truth will make your life better and the chaos I had for managing which images had their backgrounds removed and which ones didn't was at the point that I was going mad so the way that image engineering works now well more importantly the way that pck thing works now is when you upload an image the background removal doesn't start until you render the result so if I upload an image and then immediately close the tab the background is never removed the background is removed when this tag is mounted on the page and that tag mounted on the page makes the image get fetched from cloudflare and if it exists it gets pulled out of the storage and given to you and if it doesn't it gets generated and then given to you while also being written to storage it allowed for me to reduce so much complexity and it made this project go from something I was ashamed of to something I'm genuinely really proud of and that's all on cloud flare but that's not part of the pick thing code base that is a separate image service and yes in order to keep things simple and stateless I find myself making microservices more and more open off is effectively a way to make a really simple microservice for your off layer and what I just described with image engineering was a simple microservice to remove all the complexity of managing the different states that an image can be in I'm very happy with the result of the those things but if you're starting with microservices and you're starting with these isolated things you're going to pick the wrong ones so start with a monolith make it as simple as possible and then the second or third time you're building it you'll realize oh these things could have been their own Services I should probably do that and you'll be able to make something significantly easier at that point what else what else what else anything really good in my package Json here oh upload thing pretty much all of my services use upload thing because pretty much every service has some use case where users can upload stuff and it is really annoying to set up upload thing I'm pumped with the service and where it is but at the same time I'm just happy that we built a micros service that solves the upload problem because I had so many projects with a ton of random S3 that doesn't have to exist anymore the upload thing code in this code base is some of the simplest stuff in it and it's so nice not having to worry about those things compared to stripe where I had to build my own internal micro services to manage who subscribed H and drizzle is my omm of choice if I need SQL I'm usually using drizzle prisma's catching up fast and I'm considering using it more in the future but drizzle is really good oh that's another really important one something that's in all of my projects T3 EnV this is a package that Julius made a while back because managing environment variables when you're hopping between projects and sharing things with others sucks and if you deploy something and forgot an environment variable you end up being a li ability and a problem for the companies whose Services you're using half or more of our support tickets for create T3 app were people who forgot an environment variable when they deployed t3v lets you scaffold out all of the environment variables you use in your project and give them Zod validation on build so now when you build the project if environment variables are missing it will not pass build and it will error with the specific missing variables and you can split between client and server it's super super nice it makes our lives way easier as we pass projects around different developers and different people is why someone like Tanner could grab my codebase and run it locally because it was much easier for us to figure out which environment variables he did and didn't need I'm super happy with t3v another one of those libraries where when I don't include it I end up regretting it later on I recommend it you should really consider it funny enough t3v is more popular than cre T3 app now because it's being used by so many people in so many other stacks and places too I get so many thanks for building this and it's amusing to me because I had nothing to do with t3v Julius just made it one day and asked if you could use T3 form like yeah sure highly recommend it env. t3g if you want to learn more it's one of the best ways to handle environment variables in your production applications if you have multiple people working on your project please try this and if not as chat has just pointed out at least make sure you're manually validating the process cnv because you will end up in hell if you are not M people in here saying they're using it it's going really well for them that's awesome to see I think we've covered most of it my Stack's a little chaotic I'm not going to pretend otherwise and my stack is more than ever very different between my projects I'm almost always using typescript I'm usually using react I'm hopefully usually using trpc I'm often using rsc's I'm almost always I'm using react I'm using react query the reason I'm drawing this this way is you can kind of draw a circle in the circle expands as the needs of what I'm building grow or the problems that I'm having get more painful but I always try to start with the simplest thing and most of the time that ends up being typescript and what you'll see is most of the time as my apps get more complex it's not that I'm swapping one part out for another it's I'm adding a part and I'm using less of simple or roll your own things in more correct Solutions as the problems I'm running into are more painful like the move from KV to SQL wasn't me removing all the KV calls in our project we still use KV heavily for T3 chat I don't see a future where our rate limiter isn't on reddis through up stash and I don't see a future where our stripe subscription management isn't also reddis through up stash but the data management for your actual things like preferences and your chaotic message history that all makes a lot of sense to have a SQL database generally speaking as long as you start with the simplest thing that solves the problem moving up to more complex things will not be too bad but moving from a complex thing to a simple thing is no longer a move it is a rewrite so if you start with SQL when you should have used a KV you're rewriting if you start with a KV and you move to SQL you're in good hands if you start with material UI and you move to Tailwind you're rewriting if you start with tail and move to Shaden you're adding new components start with these simple pieces and if they don't solve the puzzle you're trying to add the ones that might actually solve it I think I've covered everything I want to here I just fielded questions to see if there was anything I missed here most of the questions are about things that I've covered in depth in other videos so I don't have too much else the only last thing is the question about servers where do I put my servers forell is cool for serverless what about servers I have done an incredible job of avoiding the need for servers for a long time now and chances are if I do actually need them I'm in one of those rare cases where I benefit greatly from having a traditional server I've already offloaded the work to Julius and Mark and their host ing it in AWS where those severely challenging server loads probably belong but by the time we're spinning up real servers we've moved away from these bespoke Solutions and we're back in the chaotic world of managing State and synchronizing it across a bunch of different things and all of the edge cases that come with it pretty much every outage we've had with upload thing in the past year has been because of servers so yeah it is what it is we're working hard to make it as good as possible but servers will always kind of sock all the other questions aren't things I care enough about to talk about I think this gives you a good look into my brain and how I make technical decisions about the stuff that I built keep it simple for as long as you can and add complexity only when necessary go out of your way to delete things whenever possible and if you deleted too much and have to bring things back that's okay too think I've said all I have to here let me know what you guys think are you going to go copy my stock or are you going to take the lessons here and go back to laravel and be happy there let me know until next time peace nerds