Tanstack Start Course Course

Traversy Media| 00:30:57|May 7, 2026
Chapters10
TanStack Start is introduced as a full-stack framework within the TanStack ecosystem, focusing on its code execution model and a type-safe router, and it covers building server functions, API routes, and deployment workflows (including a Render hosting example). The video promises a crash course on how it works and how to get started.

TanStack Start is a lightweight, full-stack React framework built on TanStack Router, with isomorphic code, server functions, and easy deployment via Render.

Summary

Traversy Media’s overview of TanStack Start explains why this new framework matters for React developers. Brad Traversy frames TanStack Start as a natural extension of the TanStack ecosystem, tying together SSR, middleware, streaming, and server functions in a single, lightweight package. He walks through creating a project with the TanStack CLI, inspecting index.tsx and router.tsx, and seeing how route trees are generated automatically. The tutorial then demonstrates dynamic routes, type-safe linking, and data loading via route loaders backed by Prisma for real database access. A key highlight is the isomorphic code execution model: on first load code runs on the server, then on client navigation it runs on the client, which can cause pitfalls if you’re hitting server-only code from the client. Brad shows how to solve that with server functions and, when needed, API routes. Deployment is covered using render.com, with a $50 credit and practical host/origin configuration steps. The video ties these concepts back to the core idea: TanStack Start makes full-stack React approachable for teams already using TanStack Router and TanStack Query, offering an easy path to an SEO-friendly, server-capable app without the complexity of heavier frameworks. By the end, viewers have a solid baseline for routing, data loading, isomorphism, server functions, and deployment inside TanStack Start.

Key Takeaways

  • TanStack Start adds a full-stack layer on top of the TanStack Router, providing SSR, middleware, server functions, and streaming for React apps.
  • Route loading uses loaders and useLoaderData, enabling data fetched on the server to be rendered in components, with a clear server-to-client data flow.
  • Dynamic routes are implemented with folder/file naming like product/[id].tsx and access to id via route.useParams, with type safety enhanced by TanStack Router.
  • Isomorphism means code runs on both server and client; initial loads execute on the server, while client navigation executes code on the client.
  • Server functions isolate server-side logic; they run only on the server regardless of call origin, preventing client-side database access issues.
  • API routes remain possible for exposed endpoints, created in a separate routes/API folder with standard HTTP method handlers.
  • Deployment with render.com is streamlined: add a start script, configure host and allowed origins, push to GitHub, then deploy with a few clicks and free credits.

Who Is This For?

Essential viewing for React developers already using TanStack Router or TanStack Query who want a lightweight full-stack alternative to Next.js, plus anyone curious about server functions and isomorphic rendering in TanStack Start.

Notable Quotes

"There's a new framework called TanStack Start that has gotten a bunch of attention over the past few months."
Introductory claim establishing the video’s focus and the product being covered.
"TanStack Start is a full-stack React framework powered by TanStack Router."
Defines the core identity of TanStack Start and its relationship to the existing TanStack tools.
"This is automatically created for us when our development server is running."
Explains how route trees are generated automatically and why you don’t manually edit boilerplate.
"TanStack Start is isomorphic by default."
States the fundamental execution model that can cause navigation-time issues if not handled correctly.
"Server functions allow us to isolate our code to be run on only the server."
Key solution to client-vs-server execution problems demonstrated in the video.

Questions This Video Answers

  • How does TanStack Start compare to Next.js for React projects?
  • Can I use Prisma with TanStack Start without breaking the isomorphic routing model?
  • What are server functions in TanStack Start, and when should I use them instead of API routes?
  • How do route loaders in TanStack Start fetch data and pass it to components?
  • What steps are needed to deploy a TanStack Start app to Render with free credits?
Full Transcript
There's a new framework called TanStack Start that has gotten a bunch of attention over the past few months. And this one isn't just a bunch of hype. What makes TanStack Start so unique is that it's part of the TanStack ecosystem. So, the same team that gave us tools like TanStack Query, TanStack Router, and TanStack DB have now given us a full-stack framework. And this video is going to be a full crash course on TanStack Start. We'll go over what makes TanStack Start so unique and how it works. We'll even set up our first application, and I'll explain the core concepts behind TanStack Start, which are its code execution model and its type-safe router. From there, we'll learn how to create server functions, build API routes, and handle data fetching. So, whether you're already using tools from the TanStack ecosystem or just want an alternative that's lightweight to Next.js, this video is exactly what you need to get started with TanStack Start. So, let's get into it. Oh, and by the way, as I was filming this crash course, I did decide to include deployment as a part of this process. I think it's important to know where and how to host our TanStack Start website. So, we're going to cover that towards the end of the video. Now, for this, we're going to use render.com to host our website. And while we've used Render in the past before on this channel, this time I got in touch with the Render team, and they decided to give us $50 worth of credits to deploy our app to use on render.com. So, that coupon code will be down in the video description. So, when we get to that point, make sure to use it. Might as well use the free credits. And with that being said, let's get back to it. There's a common problem when it comes to building out applications with React. React gives you everything that you need to build out your UI in the form of a SPA or single-page application, but it leaves all the server-side stuff up to you. This means that you're building out your back end separately and then connecting to your UI via API endpoints. One of the particular limitations that developers have had with building out single-page applications with React is SEO. Search engines can't really crawl your website since everything is rendered on the client-side, and this is exactly when developers reach for full-stack solutions like Next.js for static and server-rendered pages. Now, Next.js has been the go-to for React developers for quite a bit of time, but it also does have its downsides. For one, Next.js does have a bit of a learning curve, and it also does force you into a certain way of building things. Developers have also criticized Next.js for being slow in certain situations and have just outright expressed the need for an alternative solution. And this is exactly where TanStack Start comes in and is so appealing to developers. TanStack Start is a full-stack React framework powered by TanStack Router. It provides us with SSR capabilities, middleware, streaming, server functions, and essentially everything we need in a full-stack framework. Now, a lot of React developers already use TanStack Router and TanStack Query, so they're already familiar with the TanStack ecosystem. So, when the project requirements call for a full-stack solution, it's really easy to adopt TanStack Start and transition into it. As the docs say, 90% of any framework comes down to its router. So, if you already use TanStack Router, you know most of what you need to understand TanStack Start and can easily adopt it and just add on the features incrementally that you need. Now, the best way for me to explain how all of this works and how to use it is just to dive on in and start building. So, let's start by setting up our first project. There are several different ways that we can create a new TanStack Start project. And in this video, we're going to use the TanStack CLI method. We'll run npx tanstack/cli create, and then I'm going to give my project a name. From here, we're going to get a bunch of different configuration options to choose from. In my case, I'm just going to go with the bare minimum, so I'll just skip through and just leave all the defaults. When you open up your project, you should see something like this. The files I want to focus on are going to be index.tsx, this root file, and router.tsx. To see what we have so far, let's go ahead and just run npm run dev. And this is going to start our development server, which is going to be hosted on port 3000. When we open up our project, we should see something like this, which is just the base code that that start command gave us. It set this up, and now we can at least see some output. Now, we're going to jump back into the code, and I want to show you how to access these pages and how to edit them. The index.tsx file is going to be the default home page to our website, and this sits within the routes folder. Now, the routes folder will contain all of our pages as well as API routes that we have inside of our application. I want to start with a clean slate here. So, in the home page, I'm just going to go ahead and clear out everything between the main tag here, and I'm just going to add in my own welcome message. Now, if I open up this page, I can see the changes that I made, and we just successfully updated our home page. The root.tsx file is our site's root layout. So, it wraps all the pages and contains the main layout to our site that you see on every page. Here, we see the header component, the children prop, which will be the actual page that you're on, and then we have our footer component. So, the header and footer will be the same on every page, but the actual page content will change depending on which page you're currently on, and that's going to be routing now works inside of our website. So, we have basic navigation. But next, I want to talk about adding in dynamic routes. It's very common that we're going to need dynamic route paths between pages and to link to those pages. So, imagine that we have a product page, for example. The page will always be the same, but the contents of that page will change depending on a specific path parameter in that URL. Now, to create these dynamic paths, we can go ahead and create a new file here with a root path name. So, I'm going to call this product, and then we're going to use the dot notation with this dollar symbol to specify that last path parameter in the name of that parameter. So, this can be any value that you want to call it. In my case, I'm just going to call this ID. So, this path is going to be product forward slash, and then whatever that last parameter is in the URL, that's going to make up this whole path. Now, to actually get this value, we can use the route use params method here, and this is going to give us access to that ID parameter. Now that I have this path parameter, I'm just going to output this in my page here to demonstrate how this looks, and we can visit this URL now, and anything we put inside of the URL parameter, we can now see output inside of the page. So, we can see that this is dynamic, and it changes based on whatever we put there as long as we match this pattern. Now, of course, the real use case for something like this is going to be to load in some data. So, if we want to load in a particular product, this ID can now be used to fetch some data or maybe searching some content. To make this a little bit more realistic, I'm going to add in an array of products here, and we're just going to render out these products and create some dynamic links. So, when we map through this, we can wrap each product inside of this link tag here, and for the path here, we can just go ahead and set it like this, and we'll pass in the ID. Now, this method technically does work, but it's not the best way of linking paths up here because it's not type safe. TanStack Router is type safe by default. So, if we want all of its benefits, we're going to go ahead and set the two parameter like this, and then we can pass in the ID inside of the params prop like this. So, this is going to set proper type safety in place, and things are going to work just more optimally. So, at this point, we've covered adding pages, we've even added linking between these pages, but next, I want to dive into TanStack Router and talk about how all of this works and what actually happens behind the scenes. We've already covered a lot of the key parts of how to use the router inside of TanStack Start and how all of this works together, but now I want to dive into what makes this possible because right now it's kind of a black box and sort of a mystery on what's actually happening. So, we have this router.tsx file right here, and this dictates the behavior behind the router. This is our entry point to the router inside of our application. This router is an instance of the create TanStack Router method, which consists of some basic configuration to make this router work, but the main part I want to focus on is this route tree value here that's passed into our router. Now, we get route tree from this file called route tree.gen.ts, and this consists of all the information about the actual routes inside of our website. So, if we open up route tree.gen.ts, we'll see all the routes within our app here. So, we'll see products, we can see about, we can see the actual home page, and so on. So, all that core information. These are essentially just route instances that make up the actual route paths here, and this is how TanStack knows about each route. This is how it can control the type safety inside of our application. These routes are then exported into this route tree instance and then passed into our actual router right here. So, this is how the router knows about all these paths. Now, the important thing to remember here is that we don't actually update this file. This is automatically created for us when our development server is running. So, anytime we actually add a new page, automatically this is added here. So, our router takes care of that boilerplate code that it sets up. It adds all that information into this route tree.gen.ts file, and then pass through our router. So, while this might look confusing, we don't actually need to touch any of this. It's handled for us, and this is how we get all of these cool features. Now, all we need to know is how to create pages, how to customize this router if we need to change something up, and just how all of this works within this system. So, that's really all it is at a high level. The router controls all of this. So, now that we've talked about the router, I want to talk about loading data with TanStack Start and how to actually fetch data into our application. For loading data, TanStack Start gives us something called route loaders, and these are just functions that are tied to routes and are called anytime a route path is matched. So, if a user opens up this page, for example, this loader function is going to be called right here. So, this is where we can go ahead and add in functions that maybe call some kind of API endpoint, make a call to a database, or make any other decision that we need to make as our page is loaded, and the data that is fetched within this can now be made available within this component. Now, to demo this, I went ahead and set up a real database, and I'm going to use Prisma as my ORM. So, I created this function here to actually get my products from my database. So, we go ahead and make a request, and this function simply just returns these products. Now, I'm going to go ahead and take this function and import this into my products page here, and now I can go ahead and call this inside of my loader method here. So, the loader is going to go ahead and call this function, it's going to make that database request, and in order to actually make these products available inside of the component, I need to return this from my loader. So, if I want something available inside of my component, I need the loader itself to return it. Now, to get the return values from our loader, we just call route.useLoaderData. So, anything that we return here, we can now access with useLoaderData, and we can render this inside of our component. So, the format here, whether we're calling an API endpoint or making a direct database request, is load it up in the loader, pass it down, then render it in your component. Now, from here, we can just go ahead and iterate through these products, and now we're rendering out real products from our database, and that's the flow of how we actually get data here. Now, there's a second edge case that I want to show you here. So, I created a function called get product by ID, and this function requires an ID parameter to be passed down in order to query a specific product from the database. So, to actually get this value here, inside of our product page here, in this route loader, we can access the ID parameter by passing in params and extracting that ID. So, this is how we can get that specific parameter. Now, from here, we can just import our get product by ID function, and we can just go ahead and call it inside of our loader, pass down the ID parameter, and then go ahead and return that product value. So, this is how we can actually get those values and pass them through. From here, it's the same workflow as before, where we get our product, then we can pass it down with useLoaderData, and then render that out inside of our page. Before we jump into the next section, I want to show you something that is a key part of how TanStack Start actually works, and instead of trying to explain it, let me just demonstrate what happens. So, if I open up this website, I can see everything works fine. I can see my products being rendered out. It means the database call was successful, and we have no issues. But, if I go to one of these pages here, so if I click on a product, all of a sudden, I get this error. Now, if I refresh the page, now the product detail page seems to work, and it only works after I refresh it. And if I want to go back to my products page, the page that was just working, I also get this error. Now, this confused me the first time I used TanStack Start, but it's not until you understand the TanStack Start code execution model and isomorphism that this actually begins to make sense. So, that's what we're going to cover in the next section, so let's go ahead and jump into that. The most important concept that you'll need to understand when you're learning TanStack Start is a concept of its code execution pattern and isomorphism. So, TanStack Start is isomorphic by default. This simply means that your code executes on both the server and the client. Now, on first load, the code is executed server-side, and on subsequent request during navigation, that code is now executed on the client side, and it's because of this that we saw the error that we did in the last section. So, I want to show you how all of this works and explain it, and also show you how we can fix what we had there. To demonstrate this, I'm going to go ahead and console out hello world inside of my products page and inside of my product detail page. Now, this way, when we open up these pages, we're going to see how this gets consoled out. So, when I refresh my page, this is considered the first load. So, we're opening up the website directly, and we're going to see hello world inside of the terminal, so on the server-side. Now, when I navigate between pages on subsequent request, we're going to see this on the client-side. We're going to see that hello world is now being executed. So, now as I'm navigating between pages, we're going to keep seeing hello world as I jump between these. So, this is what isomorphic means. This is done for a very specific reason, and it's actually a brilliant concept because you get the best of both worlds. You get server-side rendering when you want some heavy server logic and the benefits of SEO, but you can also go ahead and let the client take care of the rest once the website is actually loaded. But, it does make things a little bit tricky for us. So, with our issue, when we called our database on the initial load, we didn't see an error. We saw the data rendered out. Everything worked just fine. But, when we started navigating to other pages, that's when we saw the error, and essentially what is happening is we were using a server SDK when we were using the Prisma ORM, and that's incompatible with the client side, and we also don't want to call our database directly from the client. So, either way, that's a big no-no. So, the goal here is to keep the nice isomorphic routing experience. We want to ensure that our database access stays on the server only. In Next.js, we have server components. So, if we wanted to call our database directly, we can do that because it's safe. And if we want to call our database from the client side, what we would do is create an API route, make sure that that code is only executed on the server, and then call the API route from our client component. So, there is clear separation there. Now, with TanStack Start, we don't have server components, but instead, we have something called server functions, and server functions essentially let us wrap our code inside of a function that will only run on the server, and this function can be called on the client side or server side, but it still creates an isolated container for the actual code that is being run. These are actually somewhat similar to Next.js server actions, where server actions allow you to mutate data, but they're not actually there for fetching data. So, you wouldn't want to use them for that. Well, with server functions, you can actually send get and post requests. So, unlike Next.js server actions, you can fetch data with them, and this is exactly what we can use to solve the problem that we just had. So, to make use of server functions, we first need to import the create server FN method. Now, from here, what we need to do is go ahead and just call the create server FN method, then call the handler method, and from here, we're going to add in the same logic that we had in our original get products function, and we're just going to go ahead and execute that code inside of the handler. Now, this code will run only on the server, regardless of where this is being called from now. So, we basically just modified the function. Now, for get product by ID, we need to do the same thing, but it's going to be a little bit different because we're passing down an ID. So, instead of just passing down an ID directly, we're going to go ahead and call create server function, call the handler method, and then we need to access this data parameter first. That's because server functions take in a single parameter, and that is data, and inside of data is where we can pass that through. So, we access the ID, and then we have our original logic here. Now, in order to call it, we just need to change what we're doing in the loader. So, instead of passing down the ID, we go ahead and pass down data, and then we throw in the ID into data, and this will make it work. So, now that we have this set up, we can go ahead and navigate between our pages, and you can see that everything works just fine. So, we're calling the database, we're calling the get product and get product by ID function, and the code inside of those functions, because they are now server functions, is being executed on the server side. So, they're never run on the client, and we no longer face this issue here. So, to recap, TanStack Start is isomorphic by default. This means our code runs on both the server and the client, and we have server functions that allow us to isolate our code to be run on only the server. Now, we also have other functions to handle different situations. There are methods like the create server only FN method, which basically says this code can only be run on the server and only executed on the server. We have the create client only FN method for functions that should only be executed on the client side, and we also have this create isomorphic function for functions that can handle both situations, depending on which environment we're in. So, they can flip-flop between those situations, we can write different conditions for them, and these are all very useful. Now, in a way, server functions eliminate the need for us to create API routes inside of our own application, but there are still use cases for when we need to create these. There's plenty of examples, actually. So, in the next section, we're going to talk about creating API routes within TanStack Start. In the last section, I introduced server functions, which kind of eliminate the need for creating API routes within our own application. We can just use server functions to handle any server-side code, but there are still situations where we need to expose some kind of API endpoint and handle raw HTTP request, whether we want to just make something publicly available, we want to create some kind of webhook, there's still use cases for it. So, this is why I want to talk about API routes within TanStack Start, because they're still plenty relevant. So, to create an API route, we can create them in the same routes folder that you create your pages. In this case, I'm going to make sure that they're separate from all of my pages, and I'm going to create a subfolder called API, and then here, I'll create my first API endpoint. We're going to use the same create file route method that we use for pages, but only in this case, instead of returning back a page component, we're going to return back a simple server handler. In our handler method, we want to specify the HTTP method, like get and post. In this case, I'm going to just specify this as get, and we're going to return a response with some JSON data. If we want this route to handle a post request, I can just go ahead and add in another handler and specify this one as post, and that's all we need to make this work. So, if I open up this endpoint, if I go to this route, here we go, we see our response, and that's as simple as it is to create an API route with TanStack Start. Okay, so now it's time to go over one of the most important steps, which is deploying our application, making sure it's hosted and live for the world to actually see it. So, in this video, we're going to use render.com. Now, Render is something that I've used in the past before. Traditionally, I've used it more for back-end servers, for my Django apps, my Express servers, but in this case, Render can do it all. It can do everything from handling full-stack applications, static websites, it can even spin up a Postgres database for you. So, it's got a lot of services, but in this case, for hosting, it's the perfect option. Now, we've used Render in the past on this channel, but in this case, as I mentioned earlier at the start of this video, I did connect with the Render team, and they did give us $50 worth of credits to actually hand out. So, that's going to be down in the video description. Make sure to use those before you deploy it. Render does have a free tier, but you might as well use the free credits if they're there. So, let's go ahead and get those credits, and let's get into it. Okay, so before we deploy our website, we need to take care of a little bit of housekeeping, just to make sure our site is ready to go. First thing we'll want to do is add in the start script to package.json. So, this means that anytime Render calls the start command, it runs a production server for all of our interfaces and on Render's port. Setting our host to 0000 means that this container accepts traffic from outside, so Render can actually forward requests to our app, and the port itself will actually bind with the port that Render assigns us. Next, we want to set some allowed host, and this is just a list of domains that can access our website. Now, if you have a custom domain, you would put this inside of this array, as well as any domains that you want to actually access the site. So, for example, when we deploy our website, it's going to be our app name, and then dot onrender.com. So, we're going to want to set these here. Now, this can be done inside of the vite.config.ts file, and here we can just go ahead and add in the preview property, which is going to be this array, and we can hardcode our domains here. Now, in this case, I don't know my app name or domain that we're going to have yet, so I'm just going to go ahead and set this as a wildcard, and typically, when you deploy this, you want to make sure that you set your specific domains, but in this example, it's going to be fine. We're just testing this out. It's a dummy app, so I can just go ahead and add in dot onrender.com, and this is going to be fine. So, that's all we need for the actual configuration. So, we added in an allowed host, we added in a start script to package.json, and next, what you're going to want to do is go ahead and push this site to GitHub. Now, I've already done this. We have our code here on GitHub, and all I need to do is go ahead and create a Render account and connect this repo to a specific account. So, we're going to do that next. So, now we want to go to render.com and log in. If you don't have an account, go ahead and create one, and once you're logged in, you're going to see something like this. Here, we're going to see all our projects. We're about to create a new service. In our case, it's going to be a web service, but before we do that, let's go ahead and get our coupon code, apply some free credits, and then we can move on to the next step. So, to apply the credits, we can go to the billing tab here, and under the credit and balance section, this is where we can apply that coupon code. Now, at this current time, the coupon code is render-traversymedia, and this can just be applied here, and our account will automatically be credited. Now, if for any reason this changes or it doesn't work, I'm going to make sure to update that code in the video description, or at least leave a comment. So, if it doesn't work, go ahead and check that out, and we'll just make sure that that's fixed. So, all right, back to deployment. Now, let's go ahead and create a new web service, and I'm going to start by connecting the GitHub repo that I have. So, if you haven't pushed your code to GitHub, make sure to do that first. And if this is your first time, you're going to have a few extra steps to go through. You're going to want to authorize Render to actually access that specific repo. So, go ahead and take care of that process, and then just walk through those steps. Once our project is connected, we're going to want to finish up under this setting section. So, make sure that we have the right language selected. In our case, if it's TanStack Start, this is going to be node, and ensure that our project is pointing to the correct branch. Now, this is going to be main, master, whatever you have, just make sure that it's actually the correct branch, and just make sure that this is set. For the region, I'm going to set this to Oregon, since that's going to be closest to where I'm at, where my users are at. If this is different for you, just go ahead and find that region to where most of your users are going to be. For the root directory, I'm going to leave this as is, but if you happen to have your main project inside of some subfolder, just make sure that you're pointing to that right directory. But, if you followed along with my steps here, leave it as is, this is already going to be your root directory, so don't change this. For the build command, I'm going to set this to yarn install and yarn build. Now, for our start command, we've already configured this in our package.json file, so all I need to do is set yarn start, and this already is configured, it's going to run that script that we set up, so we don't have to change anything here. From here, we can just choose the instance type now, and in my case, I don't want to deal with any cold starts. I have the Render credits right now, so we're just going to select this starter option here. Now, the rest of the configuration is up to you. If you have any environment variables, this is where you would set those, and under the advanced tab, I'm going to leave this as auto deploy to on commit. So, anytime we make a change to our main branch, this is going to trigger the auto deploy, and this is where we can control that. So, from here, all I have to do is click deploy, and we're going to let Render do the rest of the work. So, as this is deploying, we're going to see all the build logs, everything that Render needs to actually deploy the site. If we have any errors, these are going to be output here. If anything goes wrong, we can see the error code, and this is how we can actually debug that process if anything goes wrong in this step. Okay, so looks like the deployment was successful. Render has given me this URL here, and because I already set that wildcard in my list of allowed host, this URL will work, and it will allow me to access the site. So, if I open this up, we can see the site is on a live domain, and we have successfully taken care of deploying our TanStack Start site on Render. So, if you got this far, congratulations. Okay, so that's the core of TanStack Start. At this point, you should have a solid base understanding of how all of this fits together. We covered everything from navigation and file-based routing, type safety, we talked about fetching data with loaders, the code execution model and isomorphism, server functions, and API routes for when you need external API endpoints. If you want to go deeper, I highly recommend you not only check out the TanStack Start docs, but you also check out the TanStack Router documentation, since a lot of what we covered is actually TanStack Router, just basically extended with TanStack Start. And that'll cover everything we didn't talk about in this course. This is a crash course, after all. We can only do so much. So, that's it for this video. I hope you enjoyed it and learned a bunch, and I'll see you all in the next video.

Get daily recaps from
Traversy Media

AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.