Modern Next.js 2025 Tutorial: Complete Full-Stack Framework Overview
What You'll Learn in This Next.js Tutorial
This updated tutorial from a top Next.js instructor covers everything you need to know about modern Next.js (as of 2025). Whether you're brand new or need to catch up on the latest changes, this guide provides pure, no-fluff value. To build a strong foundation, consider starting with a Comprehensive Full-Stack Developer Course Overview & Learning Strategy.
Key Architecture: Client vs. Server Side
Next.js is a full-stack framework with both:
- Client side: Runs in the browser
- Server side: Runs on the server (most critical)
Unlike traditional React apps (like with Vite), Next.js allows you to handle database operations, API keys, and heavy computations directly on the server , all in one app.
🧩 Core Next.js Concepts Explained
Server Components vs. Client Components
- Server components (default): Run only on the server; ideal for data fetching from databases or APIs
- Client components: Use
"use client"directive for browser events (click, state, effects) - Best practice: Create small "islands of interactivity" , keep most components on the server
Data Fetching
- Fetch data directly in server components using
async/await - No need for
useEffect, data is fetched server-side and HTML is sent to the client - Use Prisma ORM or similar tools to interact with your database
Routing (File-System Based)
| Route | Folder Structure |
|-------|-----------------|
| / | app/page.tsx |
| /posts | app/posts/page.tsx |
| /posts/[id] | app/posts/[id]/page.tsx |
- Dynamic routes use square brackets
[param] - Access URL params with
await params - Special files:
loading.tsx,error.tsx,not-found.tsx
Server Actions (New!)
- Functions that run only on the server but can be triggered from the browser
- Use
"use server"directive - Perfect for creating, updating, or deleting data (CRUD)
- No need for manual API endpoints , Next.js creates them automatically
- Combine with
revalidatePath()orrevalidateTag()to update UI after mutations
Caching with use cache (Latest Feature)
- Granular caching for specific data fetching functions (not whole routes)
- Use
cacheLifeto set expiration - Tag caches and revalidate on demand with
revalidateTag() - Better than older fetch-based caching , cleaner API
Partial Pre-Rendering (PPR)
- Enable with
experimental.cacheComponents: trueinnext.config - Combines static and dynamic content: Static shell is pre-rendered; dynamic parts (e.g., user-specific data) stream in later
- Wrap dynamic components with
<Suspense>for streaming
Route Handlers (API Endpoints)
- Traditional REST API endpoints (still useful!)
- Folder:
app/api/posts/route.ts - Export named functions:
GET(),POST(),PUT() - Ideal for webhooks (Stripe, CMS notifications)
Proxy (Replaces Middleware)
- File:
proxy.tsin project root - For quick modifications on incoming requests: redirects, rewrites, A/B testing
- Not for heavy computation or database calls
- Authentication checks possible (optimistic, cookie-based only)
🤖 AI Coding Agent Updates
Next.js now includes built-in AI agent support:
agents.mdandclaude.mdfiles with version-specific instructions- Pre-packaged documentation in
node_modules/next/docs - Browser log forwarding: Client errors sent directly to your terminal
- Agent dev tools: Agents can inspect components, take screenshots, and monitor network activity
🔐 Authentication with Kinde (Practical Example)
- Create a Kinde application and install the package
- Add environment variables (
.env.local, already gitignored) - Create route handlers for Kinde's callback URLs
- Protect server components with
getKindeServerSession() - Protect server actions and data access layers
🚀 Deployment Options
| Option | Features | Best For | |--------|----------|----------| | Managed Platform (Vercel) | Full Next.js support, auto-deploy | Most users | | Dockerized | Full control, cheaper | Tech-savvy developers | | Static Export | HTML/CSS/JS only, no backend | Simple sites, SPAs |
🔍 Quick Reference: Build Output Icons
During npm run build, routes show different icons:
- ⚪ Static (SSG): Pre-rendered at build time , fastest
- 🔵 Dynamic (SSR): Rendered on each request
- 🟣 PPR: Static shell with dynamic streaming
📌 Pro Tips
- Use the Link component instead of
<a>for client-side navigation and automatic prefetching - The Image component provides automatic optimization and prevents layout shifts
- If a dynamic API (like
cookies()) causes a route to become dynamic, isolate it in a separate component with<Suspense> - Validation and authorization are still required for server actions , treat them like public API endpoints
✅ Summary
Modern Next.js is:
- Full-stack: One app, both frontend and backend
- Server-first: Most logic runs on the server
- Highly cacheable: Multiple levels of caching for optimal performance
- AI-ready: Built-in support for coding agents
"Next.js can be very confusing if you don't understand the concepts. Even if you use an AI coding agent, you should still understand what's going on under the hood." , Tutorial Instructor
To see these concepts in action for an impressive project, check out how to Build a Modern Frontend Developer Portfolio Using Next.js, Tailwind CSS, and Sentry. For a deeper dive into styling, explore Implementing Your Own Design System in Next.js. You can also see how to architecture a full app by learning to Build a Full-Stack LMS with React, Node.js, MongoDB & Stripe. If you're curious about other frameworks, take a look at Getting Started with Svelte: The Ultimate Beginner's Guide.
Welcome to this tutorial on the latest Nex.js. In this video, I'm going to give you a complete updated overview of
Nex.js at the time of recording. So, if you've never done anything with NexJS, this is the place to get started. But
actually, also, if you're already familiar with Nex.js, this is still a great video to watch as well because
we're going to discuss some of the latest changes in the video as well. I'm Wesley. By the way, I've created some of
the most popular videos on Nex.js. So, this one, for example, almost has half a million views. And this more advanced
video actually also has hundreds of thousands of views and people are still enjoying them, but you can see they have
been created a few years ago. So, I think it's time that we have an updated overview here. So, some of the new
things are of course with AI. So, we're using AI coding agents now and there are some AI specific things that I think you
should know about in Nex.js. There have been some updates to caching. We have something called proxy now instead of
middleware. So there's a bunch of little changes that I'm going to add in the video as well. To explain NextJS, I have
created this uh diagram that I will use throughout the video. And also I have a very simple blog website, right? Because
with NexJS, we create websites and web apps. So we should be able to create a very basic site. But as you'll see, a
very basic site already has a bunch of those concepts like server components and client components. And we want to do
data fetching. There's a bunch of caching and routing. And there are server actions and route handlers. So
even a basic site already has a bunch of those concepts baked in as well. So that's what we're going to look at
throughout the video. I will go through it pretty quickly. There's basically no fluff in this video. It's going to be
pure value. So I recommend that you watch the video in full because nextjs can be very confusing and frustrating if
you don't really understand the concepts that we're going to discuss. Even if you're going to use an AI coding agent,
I think you should still understand what's going on and how everything fits together. So let's just jump into it.
And by the way, this video has been made possible thanks to today's sponsor which is kind. I really like them for using
authentication in next.js. So you can find a link in description if you want to know more about them. All right. Now
to understand Nex.js, we need to zoom out a little bit here and understand the pieces it consists of. So one NexJS app
has both a client side. This runs in the browser as well as a server side. This runs on the server side. And this may be
a little bit different than what you're used to. So if you've been using uh VIT, React Vit, you you may have created
React apps before, but they basically only had a client side. So everything was running in the browser. So with
NexJS, it's a full stack framework. So there is also a server side. And in fact, I would argue maybe even most of
the things that you're going to think about have to do more with the server side. This is actually very powerful
because on the server side, we can do typically more things. we can do more computationheavy things or we can use
API keys to reach out to other uh services like an open AI API. We can interact with our database and so
typically we do those things on the server side not on the client side. So even if you had a react v app before you
still needed some kind of separate backend app like NodeJS to do things like update the database with NextJS is
different. You just have one app for both client side and server side. So in terms of React components, we have
server components and client components. And actually a lot of the components are going to be server components, meaning
they are rendered. They run only on the server side. And you can do things in there like fetch data from your
database. For example, you can fetch data in there and then it will be rendered on the server side and the
result of that is sent to the client. But there are also client components. they still render in the browser. And
you want these when you need to hook into browser events. Like if a user clicks on a button, for example, there's
a click event and we want to hook into the click event. Well, in that case, you need to use a client component. Or if
you want to use React hooks like use state and use effect, that can only happen in the browser. So for some
things, you still need a client component. We'll see some examples. There are also server actions.
Typically, we get data from our database, for example, in a server component. But what if you want to
update data like add a new post or edit a post or delete a post. We can now use server actions for that. These are
basically just functions that run only on the server side but can still be triggered from the browser. Next.js
behind the scenes will make sure that the if you submit a new post for example that the data from the browser goes to
that server function and in that server function you can update your database for example. It really abstracts away
the network boundary and makes for a very ergonomic way of updating your data. Traditionally you would use API
endpoints for that and we can still create those if we want on the next.js server side. We can use so-called route
handlers for that. So you can have get post put API endpoints just like before but then you have to manually send the
data from the browser to those API endpoints. So many times we actually prefer using a server action instead.
However, you may still want to have API endpoints for example for web hooks, right? So if you're using Stripe,
somebody paid, Stripe is going to send you a request with the information about that payment. It needs some place to
send that to. Typically, that is an API endpoint, a post API endpoint for those incoming web hooks. So, that's enough
talking. Let's actually try to create a new Nex.js app. I have opened a folder here in my code editor. I'm going to use
Visual Studio Code, but works the exact same in Cursor or other IDEs you may be using. I will open up a terminal here,
and I'm going to run MPX create next app. And if you want the latest version, you can do at latest. Now, this will
create a new folder in here, and then put all the files in there. But I just created this folder on my computer. I
wanted to put everything directly in here. So I'm going to add a period here at the end. Now I'm running this myself
in the terminal. However, you could also ask your AI coding agent to spin up a brand new next.js app. However, I still
like doing it myself. It has basically zero error margin if I do it myself. So I pressed enter here and you can see
it's going to ask me about the version and the packages. I'm going to say yes. So these days it has some recommended
defaults. So we do not have to decide point by point here on all of these options. It just has one basically
starter package. I will go with all of the recommended defaults and then we get all of those files here and it's
immediately going to install the dependencies as well. All right, with a few seconds all of that is finished.
Let's actually take a look around here at what we have now. So with the new uh starter app essentially with create next
app we get the following. We have a bunch of configuration files right here in the root very typical of JavaScript
project right because we're going to use TypeScript for example. So there are some TypeScript settings. There is post
CSS used by Tillwind and we're going to use Tillwind to style the app. There is some configuration for Next.js itself as
well. ESLint right for linting. There's a readme file here basically a quick uh description of what the app is doing.
And of course we have package.json which is a description of our project and this also specify the packages that our
project depends on. So our project needs these dependencies to run properly. So for example, we have the React package.
we need this installed. Now that package itself may also have other dependencies, right? And those dependencies may also
have their own packages they depend on. So there's like a tree of dependencies. So the complete tree is described in a
package lock.json file. This is pretty big, but this allows other people to replicate exactly what you have here
locally as well. We have git ignore because we don't want to include everything in our git repo, right?
Environment variables. We do not want to accidentally push them to GitHub for example. So we want to ignore EMV files
and some other files as well. And then we have two new markdown files here. These are for our AI coding agents.
We'll talk a little bit more about this in a second. So then we have this next folder. This is just something next uses
by itself. We have note modules. This is where we actually have the installed code of those packages. We have a public
folder here. These are like static files like images or maybe videos or PDF files that you want to use in your app. And
then we have the app folder because this is a Nex.js JS app router project. Previously we had the pages router. So
here in the app folder we have a page.tsx right here in the root of that app
folder. This means this is going to be the homepage. So here we have a bunch of markup essentially by just a react
component. This is a special name page.tsx. So this will automatically become the homepage and whatever we put
here is going to be displayed on the root of the domain. Right? So, domain.com uh slash perhaps, but just
basic just a homepage. We also have a layout.tsx file. This is basically going to wrap the pages. So, we'll talk a
little bit more about this in a second, but basically every page is going to have a body and HTML tag because a page
will just be sandwiched in here. We also have globals. CSS for styling. And we have FAF icon. This is also a special
file for the FAF icon. Let's actually start running the app so we can actually see it in the browser. I could ask my AI
coding agent to spin up a dev server or I can run it myself. I can see here in the script that there is a dev script.
So I can open up the terminal clear and do mpm rundev. This will give me URL. I can commandclick on this and actually
these days it opens it up inside the IDE. So if you like that layout you can do that right here. However, I do prefer
to actually work directly in the browser myself. And this is the homepage right. So what we see here if I move this a
little bit this is the homepage. So if I go to the app folder and then here the first page.tsx file this is being
rendered here because I am on the home route right? So just forward slash basically if I edit something here like
if I just say to get started exclamation mark exclamation mark and save it automatically updates the page here. So
now we have an update here. Notice that in XS app you often also see this widget in the corner. This has been around for
some time actually but this is basically going to give you some information about the current route that you're on. So I'm
currently on the homepage. It's telling me it's a so-called static route. We'll talk more about all of this in a second.
So basically some developer information here. You can disable this if you want. You can hide it if you want. Let's talk
a little bit about the AI specific updates that we have in Nex.js. So we just saw that there are two new files
here. There is a clot MD file as well as an agent.m MD file. So these are for your AI coding agents. Cloud code will
automatically look for cloud.md in your project and the other coding agents like codecs will look for agents.md. So what
you'll see often is that the cloud.md file is just referring to the agents.md file. So we can just put everything in
one file instead of duplicating it for both. So clot code will be referred to agents.md. So all the coding agents will
land on this one. And these are basically going to be some instructions for your AI coding agents because these
models are often trained on some older data and XJS has some more tricky or subtle parts of it that coding agents
sometimes got wrong. So they have added this now as part of this default starter app so that agents are always aware of
these conventions for the right version that you have. Right? So your next JS app is now coming here with instructions
specifically for the version that you're using. So it says here read the relevant guide in note modules next docs. So if
we look it up note modules. So the coding agents will be looking in here and here we have an index.md file and
basically this contains a nextjs documentation. So the AI coding agent does not have to go out there on the
internet. The documentation is prepackaged here with your app. So here it describes what next.js is and it
refers to these other files. So here there is the app folder. So there is information here about getting started.
for example, how server and client components work, right? So AI coding agents often had a little bit of an
issue with this. But since this is not prepackaged, that should be much better. And there's also information here about
fetching data and also proxy, right? This is also something new. AI coding agent previously may have accidentally
used middleware, but now because this file is included, it should know that it's proxy, but it now also knows when
to use it, right? So we'll talk a little bit more about proxy in a second. So basically a bunch of up-to-date
instructions for your AI coding agent. In fact, I actually like reading this myself as well. So you may want to go
through the files yourself as well just to learn about it yourself. The other new thing is browser log forwarding to
your AI coding agent. So as you're developing your app, there may be client side errors and previously you would
have to go into your browser console, copy them and give them to your AI coding agent. Instead, you can now
enable in the next convex this browser to terminal option. So I what I could do is I could go to next config and I could
paste that right here and then by default it will only send errors to the agent but you can also have all console
outputs for example but it may take up too many tokens but now this should send the logs to my agent. Now from my
understanding you do need to run the agent then in a terminal and it itself needs to start the dev server. So I
stopped the dev server here as previously I I was running it myself. Now I could use clot let's say or codeex
and I could say something like start dev server and it will basically just run mpm rundev for me. So now we can see the
dev server is running. It's just that it's managed by clot. So now when there are uh errors it should be able to be
notified because it has access to the output of that dev server. Now about running those dev servers if you've been
using nextjs before with these AI coding agents you probably noticed that they're very eager to start running a new dev
server. So there is a solution to this now in that next folder. Basically it's going to keep track of the dev servers
that are running. So here nextdev here there's a lock file which describes which dev server is currently running.
So if your agent is trying to start a new one, it next will give it information about the current one that's
already running. So this should help with your agents managing those dev servers for you. And finally there is an
experimental agent dev tools option as well. So it's building on the next browser package. Basically, an agent can
control a browser and it can interact with the app through that. So, it has maximum information about what is going
on. So, it can do things like inspect the React componentry. It can analyze so-called PPR shells. Basically, uh we
want to cache as much as possible on the page. We'll talk more about this later. It actually also get access to errors
and logs. It can monitor network activity and can even take screenshots or record uh little videos. If you want
to try that, you can install it as a skill. But I think you should know a little bit more about what it actually
means before you start using it. So let's actually continue explaining how NexJS works. All right. So we have this
basic next.js app. But we want to build a blog website. So let's actually go ahead and do that. First of all, we have
this title in at the top of the page. We still have this default. So this is some metadata. We can go to layout.tsx here
to see the metadata. So here we have a title. We actually want to have next blog here and a description which is
something about blog. This also shows up on Google search rankings or if people ask questions about the website in an AI
app, the AI chat may use this information. You now if I go back you can see I have this title here which is
not the same as what we want. Of course the homepage here is just the boiler plate. We want something like this.
Welcome to my blog. So if we want to change this, we go to that homepage which is just the page here in the root
of the app folder. And here typically what you would be doing is you or your coding agent will simply remove a bunch
of things here. And actually the only thing I want here is an H1 welcome to my blog. But now everything is gone here.
The text is here. But this is not the proper styling yet. This looks way different. And that's because there is
also a bunch of styling in the layout file. So this is page specific. So this is just for the homepage. But a lot of
the things that we want to style here like the background color here, this this grayish color, a lot of those
things we want to have on every page, right? So here on the posts page, I want the same styling as on the homepage. So
if it concerns multiple pages, you often work with some layout file. So of course, every page should have HTML and
body tag. So here I changed some other things. So now we have the proper styling. Now what did I do here? Because
this looks a bit strange with children. Basically, you have to imagine every page. Right now we only have a homepage
but we're going to have a posts page. Those pages will become the children here. Right? So you have to imagine the
layout wraps the pages. It sits around the pages. Right? So here I have page.tsx will become in here. Right? So
whatever I have as the page in this case I only have this H1. If I copy this you can imagine that this will become like
this. Right? If I go to a different page that page will be sandwiched in here. Right? Because of that, on every route I
go, home on the home route or SL posts, they will all be wrapped inside a main tag, they all have body and HTML, and
they all have this overall layout here where we have this uh styling here with a grayish background color and this
white background color here in the middle. Right? So, this is the overall layout of the site. I want this to
affect every page. So, that's why I put it here in layout. And this is actually very powerful because if I go here to
the example, if I navigate to the post route, it's only the part in the middle that has to change that is rerendering.
Everything else that I see here can stay the same when I'm navigating between route. So the header here and the
footer, they can stay the exact same. It's only the part in the middle which is actually coming from page.tsx that is
being swapped out, right? So that's being swapped out here. Everything here around it stays the same. So we actually
want to add a header like we have and a footer like we have here in the example to our blog site as well. So I can
simply add a footer here below the main here in layout because I want the footer to be present on all routes not just
home route also post route. Now if I go here you can see I have a footer here but we don't have a way to navigate yet.
Typically we do that with some links in the header. So let's add a header. So typically we have a header on top of the
main tag right this is all standard HTML semantic tags. So I added a header here because I want this on every route,
right? Same header. So now I have this header and we see some links here and we also see an image. Let's talk about
routing here. So what I added here is we have some markup here now for linking to other pages. So traditionally in HTML
you would use an anchor tag for that, right? So I can still do that if I want, right? So you would have an anchor tag
with href. Now, if I would use it here, when the user clicks on that, it would request a whole HTML page from the
server. You could say like a hard navigation. However, there's something better here in Nex.js, which is we can
use the link component. In that case, as we just saw, it only swaps out the part that needs to rerender, right? So, only
the page.tsx, right? The other things like the header and and footer, they can just stay the same. So, it's more like a
soft navigation. It also feels more smoother to the user. So, you just use the link component for that. We can
point it to the route. So / post. You can see here I have I can hover post. If I click on that, I will go to /post. The
header and the footer stay the same. But what we will see here is the page.tsx for that particular route. However, we
have not created this yet. Right? So routing here is done with the file system. So if we want to show something
on /posts, we have to create another page.tsx here. And it works with the folder structure. So I can do a new
folder here called posts because I want something for /posts. And then in there I have to put the other page.tsx. So
here I have some markup for the posts page. It's just a react component. Whatever you export here will be
considered that page. I can name it whatever I want. I'm calling it posts page. It's just a bunch of markup. Just
a div with some h1. So now when we go to /posts in the browser, this is the one that will be served. But basically that
markup is going to be put sandwiched in between here. So if I go back to the example, I have home here. Now if I
click on posts, you can see I'm navigating here. Header and footer stay the exact same as I'm navigating between
home and post. The other benefit of the link component is that it does prefetching as well. If a user goes to
our homepage, very often they will go to the posts page as well. And because this link is currently already in view,
NextJS behind the scenes will already prefetch that route. So when the user is ready to go there and actually clicks on
there, it will be very fast. It does not need another network request because it has already fetched it in the
background. This can make the app feel really snappy. However, by default, this is only enabled in a production build.
So when we actually create an optimized version of the app, this will be enabled. Currently, I'm running a dev
server, right? So we're in development mode here. So this is not enabled. So I cannot demo it to you right now. So by
default, when a link comes into the viewport, it will be prefetched behind the scenes. If you're using the link
component, you typically want to keep it enabled. However, if you want, you can also disable it by doing prefetch as
false. For example, if you have a footer with hundreds of links that people aren't really going to click on,
typically it may be a little bit wasteful to to prefetch all of that. So, there are some scenarios where you want
to disable it, but typically you want to have it. Note that we also added a logo here. So, here we can see I'm just using
the NextJS logo here as my website logo. Traditionally in HTML, I could use the plain image tag. I can still use that if
I want, but there is also this dedicated image component that Nex.js offers. It comes with a bunch of optimizations for
the image out of the box as well. For example, if you have a large image on the page, it may shift the content.
Maybe you've seen that before. So, you can specify the width and height here to help prevent that content shift. But it
can also do things like create bigger and smaller versions of your image. So depending on the device of the user and
on which width they are viewing your page, it can serve an appropriately sized image. This can make it faster and
basically overall better performance for your images. In this case, I'm linking to an SVG file. I can just use forward
slash because I already put this or it comes by default here in this public folder. Sometimes you want to link to an
external image. For example, I use this image for my bitegrant.com homepage. I'm hosting it on Claudinary and you can
just specify this here. On older versions in Nex.js, you first have to confirm that you want to allow images
from this domain. So, previously you had to go to next config and enable that here. However, now when I try doing an
external URL like this, I actually don't get a warning anymore. So, my guess is that they changed it. However, on older
versions of NextJS, you will for sure get a warning and you first have to enable it in the next config file. But,
they will describe how to do that or your AI coding agent can do it. Now, people typically expect to be able to
click on the logo to go to the homepage. So, I wrapped this with another link component. So, if I'm on /ost, but I
want to go to the homepage, I can click on this and I'm navigated to the homepage. We have a bit of a messy
layout file here because we have a header here and it's not in a different component. I just put it with everything
else here. So, typically, of course, we split up our application in React in components. So, I could create a new
components folder directly here in the app folder. you can sort of colllocate it with your routes. However, I
personally like using the app folder just for routing purposes. So, if I want to have components, I may create a new
folder outside of it. So, I have components here and here I could create a header.tsx file and I could just
create a header component here and just put all of this markup essentially here. It will clean things up a little bit.
So, let me import things here and then we can just use this component name instead of all of this stuff over here.
Just import it. And now I have this works the exact same as before. We can do something similar for the footer
component. So we can create another component in here and say footer. We can copy the footer from here and just copy
the component name and just put that right here. Now we cleaned up our layout file here. Everything here still works.
This is the folder structure I like but you will see other people with different folder structures. The thing is that the
app router in XJS works with the folder structure. So if you create a folder called post, that will become /post,
right? So that that's what we have here. When you add page.tsx, so I find it a bit confusing once people start adding
other types of folders in there as well. So I prefer the cleaner separation, but that's more of a personal preference.
Let's talk about data fetching because of course when I go to /posts, I want to see a list of posts. So there is this uh
dummy API that we can use. Basically it will just give us a bunch of JSON data with a bunch of dummy posts. So a post
will have a title and a body. How do we fetch this data in nextJS? So if we go back to this diagram before if you were
doing a client side only react feed type of application, you would have some kind of use effect. So that use effect would
make some kind of API call to that dummy API and you would get back some data. Now we could technically still do that
in X.js. You would create a so-called client component. We'll talk more about it in a second and we can still do use
effect. However, typically in XJS are going to fetch data directly from the server side. So far we've only been
using server components actually and again we'll talk more about the differences but one of the things we can
do is we can fetch data directly from there. So we can make this API call. We will get data back. We can render that
on the server side and the result will still be sent to the client. So we can still see it. But basically the data
fetching happens directly here on the server side. So if we go to /post, we have the page.tsx. This is a so-called
server component. The components are server components by default in next.js. And what we can do in here is fetch data
directly. So I can do await fetch. Now if you want to use await, I do have to add async here. So we can do async and I
can make the fetch call to that dummy API endpoint. I will get some response and it's going to be a bunch of JSON. So
I'm going to parse that as JSON. So we get a normal JavaScript array here with all those posts and then we can just
render that here on the page. So, I'm just going to add some markup here. So, we take those posts. I'm just going to
use the top five because we I don't want to have a huge list. And for each of the posts, I'm going to create a li and
actually also a link. So, we're going to display the title of the post. We're going to uppercase the first character.
And of course, we also want to be able to click on it to go to the individual post page. We haven't created that yet,
but this is basically data fetching from a so-called server component. We can use the data here to render the markup here.
And the result of this is still sent to us in the browser. So now if I go to that / post, we can see we have five
posts here. I have just fetched data in my nextjs app from a server component. Right? So the server component here is
uh this one here. It got the data from that API and then it rendered that on the server side. When I say rendering a
component, it basically just means running all the statements inside the function body here. So it just runs this
code and it computes this into some result and so this mapping here it will be computed into some result that result
is still sent to us here in the browser that's why we can still see this server component or at least the output of the
server component. So we do not need use effect. We can do directly here in the component body like this. And there are
some benefits here. Right? So if I needed an API key to fetch the data I can just include it here because this
will only run on the server side. If you were doing use effect on the client side, it becomes a bit awkward when you
need an API key. Okay. Now I also have a link here for an individual post because here if I click on the first one, I want
to see the details of that particular post, the actual content of the post. So here I'm using the link component again,
but now I want to make the ID of the post part of the URL. So I'm using posted ID here in the href. So now if I
click on this one here, you can see I'm being navigated here to /ost. However, we do not have a page.tsx yet
that is corresponding to this uh route structure. Right? So we have one for slashposts, right? So we have a posts
folder here, but we do not have anything for something that comes after it. So if we want to serve something after it, we
have to create another folder and this is a dynamic parameter in the URL because it could be one, it could be
five, it can be some other number. So here I'm going to use square brackets here and I'm going to call this the ID.
So I'm using square brackets in folder. I'm going to create another page.tsx file. Right? So you're going to have a
bunch of page.tsx files in your next JS app. So here I have some markup for that particular page. Um I just hard coding
some post data here. So, we're going to display the title and the body of that post. And now, if I go to slash one, we
see a title here and body. Okay. If I go to /post 54, I see the exact same. So, this is
just hard coding one particular post, it does not properly show the content of the post I'm clicking on. Right? So, if
I click on the first one here, I want to see that particular one. So, in order to do that, we have to fetch data for that
particular post. So that dummy API allows us to do that because it has uh the ID here. So if I want to get the
individual post data, I have to add the ID here to the URL. So if I do number one here, you can see I get the data for
that particular post. We just have to fetch data again just like we did in the /ost page, but then we have to add like
slash one. So let's actually try doing that. I'm going to copy this. And now instead of hard coding this, we're going
to fetch data here. And again, I have to make it async. And now I need to add /ash one here to get the post data of
post with id of one. Okay. So now we are going to get JSON again but it's going to be one post. So now uh I have this
right. So markup stays the same. Now if I refresh here we can see the data of that particular post. Right. So now if I
go to slash posts I I click on this one with an ID of one. We indeed see its title and its content. But of course, if
I go to some other one like this other one, if I this one has an ID of two. If I click on that, we actually still see
the same data as the post with ID of one. And that makes sense because every time we are making an API call to /ash
one. However, here when somebody goes to our page here with an ID of two, of course, it should be two. So that's why
we have the concept of a dynamic route parameter because here I'm using square brackets. This means we can get access
to whatever is in our URL. In this case, we want to grab the ID from there so we can render the right uh result, right?
So, we want to get the right post data and we can only do that actually by looking at the URL. Remember, a user may
also come from some other place. Maybe they're sharing it with somebody else and somebody else copied the URL and
pasted that here and goes here. So, the only way we can render the right uh data here [clears throat] is if we actually
look at whatever the user had written in the URL. So, we need to get access to whatever ID is in the URL. So how can we
do that? Well, we get access to the parameters of the URL. So here for the page here, we can use params and this is
typed in a certain way. I have a different video on TypeScript in React. It's I highly recommend you watch it. We
can use this to extract the ID. So I can do await params. We have to do a weight these days. I mean it's been around for
some time but uh it is async now. So we can get the ID like this. So now I know the ID that's in the URL. So now I can
use that to fetch the right post data. Right? So it would be like this /ost and whatever ID is in the URL I want to grab
that particular posts data. So now if I go back here you can see when I have number two in the URL I do in see this
key as ess. So if I go to post if I click on this one I can see that particular uh title. If I click on the
last one uh I can also see that particular title and it's different body content. So now it's displaying the
right post data depending on what is the ID in the URL and we can serve all of those different ids with just one
page.tsx because we can change the output here depending on the parameter in the URL. We get access to that with
params here. Now why is the name of that ID? Well, that's because I gave it this particular name in the folder. So I'm
calling it ID inside the square bracket. That's the name you have to use to extract it from the param. Once we have
the ID, it's just a matter of fetching the data for that particular ID. So that's a dynamic parameter. Sometimes
you also have a search param. So if you have filters on the page, for example, a color filter for some kind of short
page, you may have something like this in the URL. Question mark color is blue. So then you also want to change what is
being displayed. So in that case, you may want to use search params, right? So that's the other option you have here as
well. However, for our use case here, we will stick to param. Now, of course, the user may type something themselves into
the URL here. Maybe some really strange ID that actually does not exist, right? Maybe there is no data for such a weird
ID, right? So, in that case, we would attempt to get data for some ID, but we would not be able to find a post. So,
here we may want to have a check. So, if there is no post, so if there is no post ID, there is some special function here
called not found. And in that case, you can see it renders this page could not be found. If you want to customize that,
we can actually create a file for that. So there's another special file called not found.tsx. This is just a react
component. I can call it not found. And I can just create some custom markup for that. So this will be served when you
call not found. So now if I do this, you can see I get not found here. But if we do use an ID that actually exists, we
get the proper uh post data again. It's just when it doesn't exist. That's another special file not found. There is
another uh special file error.tsx. So maybe the data fetching here is an issue and it throws an error. In that case, we
may want to display a custom error uh component instead of the default one. So that's another one. And there's also
loading.tsi because you can imagine that the data fetching may take some time. So I could do something with loading dot
dot dot. Right? So actually this will be used by default as long as it's fetching here. So if we just artificially add
some uh time here. So I'm just going to add like 3 seconds of uh loading time. So now if I refresh here, you can see
it's automatically displaying whatever the content is of that loading file. I will remove these for now, but it's good
to know that there are other special files in next.js as well. So that's a very simple example of data fetching in
a server component. We may also want to interact with our own database actually very common. Let's talk about that now.
What if we want to get data from our own database, right? Typically also something that we do from the server
side. So, so far we've been using the fetch API to fetch data from some third party API endpoint. But of course, very
often we have our own database and we want to get data from there. Now, often we use an OM to deal with our own
database. So, in this example, I'm going to use Prisma. So, if we go to /posts, I want to see a list of posts. But let's
say it's coming from our own database now. So, let's go to that page. Here we are fetching data. We were using that
dummy API. Now, I'm going to remove this. we will get the post some other way. Basically, Prisma helps us interact
with our database. There are other OMS, but the idea is that now we're interacting with our own database. So, I
want to get all the posts from my database. And again, I can do it directly here from this server
component. I do still have to use async weight. I get the posts here. And the markup stays the same. We're just
mapping over that here. Now, if I go here, we actually see an empty page. Obviously, we see the title, but I don't
see any posts. Well, that makes sense because when I inspect my own database, it is empty. There are no posts here. So
if I insert a post, let's add some content here. We can call this post is awesome. I can do the title first post
and it has zero files. We'll talk more about f. But now I have this uh post. I'm going to save here. I'm going to
write this to the database. Now we have one post in the database. Now if I refresh here, we can see this particular
post because when I refresh, this component is rendered. Meaning the statements inside of here are run.
Basically, it's just going to make this Prisma query to our database and then we render that into some output here. So
now when I click on this, I want to have that particular post data, but that should also come from our own database
now. So if we go to the ID page here, we were still using fetch. Well, that should not also be different. We still
want to get the ID from the URL, but then we're going to use Prisma to get the right data for that particular ID.
So I do need to cast it to a number cuz we get a string by default from URLs. So that should still give us a post and
then we still render that into some markup here. Prisma helps you with the types as well. So it actually is telling
us well the ID could also return a not a post found. So we could actually add a guard here uh like before just to get
rid of the type issue here. And actually my Prisma schema is not calling it body is calling it content. So if I save here
and now if I click on this I see the first post title and its content right here. Right? If I add another post, I
can say is cool too. I'm going to save here. Now I have two posts. Now if I go to slash posts, we see two posts. Click
on the second one. We can see its content. So this is an example of getting data into our app from our own
database by using an OM and that's actually very easy in a server component. So the server component is
getting the data from our own database. It's using that to render the component. So all the statements inside of this
React component function are run. It produces some output here, right? So it's using the data here to produce some
output. That output is then still sent to the browser. So we can still see the result here, right? We still see the
result of that server component rendering a and some output. All right. So now that we know about fetching data,
we need to know a little bit about caching related manners. Let me actually change it back to the fetch API. So here
I'm fetching data with just the fetch API. So here we're getting all the post. We're mapping over that and that's what
we see here on the posts page. Now there is actually already some well you could say default caching out of the box and
this is apparent when we run a production build. So right now we are in development. This is just for us as
developers to develop the app. But at some point of course we want to serve the app in production meaning live on
the internet so that other people can use it. We want to create a production build for that. So we can see that there
is actually another script called build which I can run here. I can do npm run build and this is going to create an
optimized version of the app and actually by default it will fail the build if there is some type issue. So
let me quickly fix the type issues. All right, I fixed the type issues. Now if I run npm run build again, it's going to
create an optimized version. It's going to do a bunch of things to make it as performant as possible. And now it is
finished. And now it has created a production build. If we actually want to run the production build, there is the
start command for that. So if you just want to try out the production build, we can do npm run start. Now if I go to
localhost 3000, I'm using the production build and actually it should feel a little bit snappier. It should be a
little bit faster actually because it is already doing you could say caching out of the box and we can actually see that
here. If we scroll up when you run a build, it will give you some information about that. So what it does is it
pre-renders some routes. So we can see that the home route and the /post route have this circle icon. That means it is
a static route. Meaning that route was pre-rendered as static content. This slash post here, this route here, we can
see the page components for that here. This was already rendered here during the build. So meaning all the statements
inside of this react component function were run. The output was created. Now whenever somebody goes here it does not
have to be rendered on demand because the HTML was already created during the build. So when the first person comes
it's already ready to go. If the next person comes it's already ready to go. This page should feel very snappy
because nothing has to be done here. We don't have to wait for the post to be fetched because that was already done
during the build. This is called static rendering also called SSG static site generation. And this actually is
something that we get here out of the box for slashposts as well as for the homepage. So the homepage HTML is also
ready to go when somebody goes here and whenever other people come there it's all nothing has to be rendered again.
The HTML is already ready to go. So this is optimal. You could say this is what we want by default. It also does it for
this not found page. But it does not do that for the individual post page. So you can see this has a different icon.
It's a dynamic page. This means it's server rendered on demand. So that means for the individual post page and so here
we have an overview of the different posts but the individual if I click here on this particular route this was not
ready yet. So this had to be rendered as I'm going there. So if we go here this is rendered meaning all of the
statements in here is rendered as I'm going to this page. Right? And then as the next person comes we're going to
render it again. And then the next person comes we're going to do it all over again. This takes longer. It takes
more resources and this is called a dynamic rendering here in next.js. Some people may also call it serverside
rendering SSR. This is less efficient but because well we have to do it every time somebody goes there. It's not
prepared yet. It's not pre-rendered yet. So why is that actually? Well, it's because Nex.js if you have a dynamic
parameter here in the URL like that. It's going to opt out of static rendering. It's going to make it
dynamic. And the reason is simply that in order for this to render, Nex.js JS needs to know what the ID is going to
be, right? So to produce output here, it needs to know what the params are going to be, right? Because the output here
depends on the prop and next.js during the build does not know all the possible combinations of the params that it could
be, right? There could be millions of different ids technically, right? And during the build, it's not going to
pre-render millions of different pages here, right? So it's not able to do that. However, there is actually a
function called generate static params which allows us to specify for which ids we do want to pre-render this page for.
So maybe let's say the top 10 or top 100 most popular articles. We can return the ids from this function and it will
generate the the pages for those 100 IDs during the build. Right? So there are ways to improve that here, but it's a
bit of an advanced topic. If you want more in-depth information about it, I recommend you check out the other video
I did solely on that. So, we already saw SSG. So, we already saw SSG here, right? The static pages and the SSR, basically
that dynamic rendering. There are a few of these other abbreviations as well, which we will see in a second, right?
So, we have to think of this as as a route, right? So, this post uh route here may have all sorts of different
components, but the entire thing, right? So we have a header here. We have that ex post page itself component. We have
the posts page component itself in the middle. Then we have a footer. But with that entire uh well view that I see here
on / posts that is being rendered into HTML and that is going to be served over and over to whoever goes here. This is
typically what we want. This is the most efficient it's going to be. Right? So if we can generate this HTML during the
build already, that is optimal. We can put it on a CDN. So when people go here, it's going to be super fast. Next person
goes here, nothing has to be computed. It's already ready to go. So if we can have static rendering, that is typically
what we want. So this /ost route is static right now. But what happens if we want to do something like recently
viewed post? Maybe we keep track of this in the user's cookie. So in order to render the recently viewed posts, we
need to read the incoming cookies. So in nextJS, we actually can do something called await cookies. And maybe that has
the recently viewed post ids or something like that. So now what happens if I save here and try to run another
build. I will do mpm run build again. And now we see something interesting. Now this /ost route is also dynamic. So
now during the build we did not create HTML out of this is now also going to be rendered on demand. Meaning as I go to
/osts it has to run all of this at that point in time. Next person comes it's going to do it all over again. So it's
going to be slower. it's going to use more resources. And the reason simply is I'm using a dynamic API meaning during
the build next.js does not know what the incoming cookies could be. It could be all sorts of combinations. So it cannot
render the output based on that because yeah during the build we don't know that it depends on the runtime information.
If you use an API like cookies or there's also headers if you want to read the incoming headers and there's a few
more. If you use any of those APIs, it's going to opt the route out of static rendering into dynamic rendering. So,
this is actually quite a common uh issue, especially with an authentication will often check for a JSON web token,
for example, in a cookie. So, it's going to have to read the incoming cookies and if you do that on a page, it may
actually opt the whole route out of static rendering. So, what is the solution here? because it feels kind of
weird that just for this little piece on the page, we are essentially affecting everything else on the page as well.
Even though this part just displaying the posts which we were doing here and also this H1 and everything else, all
the other UI is not really concerned with that but it's still affected by this. So actually one way to solve this
is to simply put the functionality that needs a dynamic API into its own component. So I could create a new
component here. Recently viewed posts, recently viewed posts and I will put the markup in here, something like this. We
would read the post IDs from the cookie store or something like that and ultimately render some output. But we're
using this cookies API in this component. So now I'm just going to use this component here instead of putting
it directly in that page component. So now it's just a component on the page. So now we're using it inside that
component. And what you can do is you can wrap that component with suspend here. With this we are signaling, hey
this piece on the page here is dynamic, right? It will basically not be created during the build. It's going to have to
be created during runtime. But everything else here can already be created during the build. Can can remain
static. During the build, we can create a whole static output here. And then for this piece on the page, we're going to
render some fallback for the initial HTML. So when a user goes to /ost, it's going to be very fast because we still
have static static shell or and initially they're going to see in place of that recently viewed post, they're
just going to see that fallback. And then later once this is finished, once this has finished rendering during
runtime, it's going to be streamed in. So that is basically suspense and streaming. So that is actually called
partial pre-rendering PPR and at the time of recording I do need to enable this by going to next config and I need
to specify cache components to be true. So cache components is a new way of dealing with caching. There are some
other things we'll discuss in a second. But now if I try to create another production build, if I do mpm run build,
we can see that / posts now has a different icon which is for partial pre-render. Meaning there is a static
shell of this route. And then for that little well you could say island on the page that needs runtime information in
order to render properly. We have isolated that we have created a boundary around that with suspense. So that
initially we're going to see the fallback in the well static shell that was generated during the build and then
later once this has been rendered it's going to be streamed into the page. So if I actually add a little bit more time
here just artificially delaying by so it will take 5 seconds before this is going to be streamed into the UI. Well I just
rebuilt and then I'm going to start that build. So now when I go to this page you can see for 5 seconds or so it's going
to show that file back. Right. So after the 5 seconds and once it is going to start streaming it into the UI and we
see some uh result of that. So the next JS docs has a nice graphic on this. So you can imagine that a lot of pages out
there or route they have some mix. So they have a lot of static content like on a product page and maybe product
information. This can already be created during the build. This does not depend on any kind of runtime information or
user information. But maybe there is a recommended products component. And this depends on what maybe the user has seen
before. Maybe they were looking at t-shirts. So it's going to recommend t-shirts here. That information is not
available during the build. And same for the cart. Maybe the user has already items in their cart. We do not know that
during the build yet. So during the build, we can already pre-render a lot of it. But the things that we cannot
pre-render yet, we're going to isolate that with a suspense boundary. We're going to render an initial fallback so
that when the user goes to that route, we can very quickly already send the static shell that we generated and then
have the result of the dynamic action streamed in later. So that is called PPR partial pre-rendering and these days it
comes with something called cache component. Right? So I just enabled that. And actually it comes with
something else as well, which is the use cache directive, which basically allows us to be a bit more granular with what
we want to cache and how how long we want to cach it. So if I simplify a bit like what we had before, we're just
fetching those posts and we're just mapping over those posts here. Now we are fetching directly in here. It could
also be a utility function, right? So you may also have something like get post and just put it in here. Then here
you would have this. So this actually does not change anything. just this is just a way of writing it for us as
developers. Right? So this does not change anything about rendering the component. Right? This is the exact same
as what I had before putting it directly in here. But we may prefer utility function. It looks a bit cleaner and we
can also use it in some other spot in our app. Maybe we want to get the post in some other place as well. Now because
I have cache components enabled, we may actually want to cache the result of this function so that uh we just have to
fetch it once and then later we can just reuse that result. So I can add use cache the use cache directive here at
the top and now I can also specify for how long the result of this should be cached maybe for hours or days. There
are some terms like that which I can specify with cache life. So this is more granular because instead of caching the
whole route here, I'm caching a specific data fetching function, right? So maybe I'm fetching other data on this page as
well, which I do not want to cache. So I don't want to cache the whole route. I only want to cache specifically this
getting the posts. Now we can reduce the amount of fetch API calls we make to this API endpoint, right? Maybe you have
to pay for access for the API access. If we can reduce the amount of calls we make, that is way more efficient. And it
would be the same with using the Prisma RM by the way. So we can reduce the load on our database if we can cache the data
fetching function like this, right? We were actually already doing that before, but we were doing it for the whole page
with static rendering, right? But now I could also use this get post on a dynamic route, let's say, but the data
fetching itself would still be cached, right? As long as I use this function here with use cache, right? So I could
export it or I could put it in some utilities file. I have lip here. I like to create utils.ts and I could put that
in there. Actually I think that's a little bit cleaner. So now we have a data fetching function here. And now I
can just import that here in my app wherever I need it. So now I know that the data fetching itself is cache.
Previously in an older version of Nex.js they did it by actually sort of patching the fetch API. So you could specify some
options here. I believe something with next and revalidate. This is different with cache components. It's a bit better
in my view because the API for specifying what you want to cache and in what and for how long is a bit cleaner.
So the first time we get the post wherever it's called in our app is going to store the result. And what if we
actually do want it to fetch new posts? Maybe we actually added a new post to our database or this API has new post
and we want to bust the cache before basically this cache life runs out. So we can still give it an a tag. I can
call it well this is going to be the posts cache. So basically giving it a name. So then in other parts of my app I
can bust the cache. So there is the update tag function. So I can call that. There's also something called revalidate
tag. So I can use this to bust the cache in other parts. For example, a server action or a route handler. But we will
see those in a second. Now it would work the same if we were using Prisma to get data from our own database. Right? So we
could also create a utility function out of this. Get posts add use cache or something like that to specifically
cache the database call. This can reduce the load on our database can make it much more efficient. But of course also
this page if we go to /ost this can still be uh pre-rendered on the server as well. So in that case this specific
call may just be part of that. So we are already caching that. So the use cache directive I would say is mostly useful
if I would also fetch data in some other place in my app maybe on a page that is not pre-rendered. So so far we've talked
a lot about server components actually. So we were getting data into a server component. There are some caching
related things that are good to know about that but we haven't really discussed most of the other things here.
So let's actually continue with the next thing here on the server side which are actually these server actions. So we've
talked a lot about getting data right this is typically what we do in server components. We get data into the app, we
fetch them or we use some kind of OM. But the other side of the equation is of course creating new data or updating
data or deleting data, right? So we have CRUD reading data and then we have creating, updating and deleting and that
is what these server actions are meant for. So server action is just a function that will run only on our server side
and in there we can do things like update data in our database. Right? So also from there we typically interact
with our database or other things on the internet can be other API endpoints of course. We want to be able to create a
new post here. So I just added a form to the page here. Very simple form where we can specify a title and content and then
click on create. So I just added that here to the page component. I could create a separate component out of this.
It doesn't matter. It would work the exact same. We just have the new post and here we have the form. Right? So
just a form like you're used to. We don't need to know all about the markup here. It's just a form. When somebody
clicks on create here, we want to submit this data to our back end. And from there, we want to update our database,
right? So, we want to have maybe a third post. This is the third post. So, now if I click on create, we well, typically
what you would do is some kind of onsubmit, right? So, on forms there is this event onsubmit, right? And then you
would perhaps send it to some kind of API endpoint that you created so that you could do something with that on the
server side. Now this is much easier now with server action. So what I can do actually and this will look crazy the
first time you see it. I can simply create a function called create post and I can add this use server directive at
the top. So this means it's going to be a function that will run only on the server side. If we pass this to a form
we will get the form data right here actually. So we can just grab the title and content from that form data and then
we can just update our database. Right? So I'm making a Prisma call here OM to add a new post. So now I can use this
function. I'm going to copy the name and we can specify that here with forms I can do action and I can just specify the
name of that server action right here. So now if I go back and I click on create. Okay. So now the data has
disappeared here. But if I check out my database here, if I refresh, I have a third post now in my database. Now if I
refresh this page, we're going to fetch the post. So we should see the third one as well, right? Because very quickly,
what are we doing on this page? We are grabbing all the posts from here. So if I refresh here, you can see I have a
third post now. So this looks really strange. So let's actually clean it up a little bit here. So technically, yes, I
can specify the function in here, but I think it looks a bit messy. So these server actions are quite important. So I
actually like to put them in their own files. So I will create an actions folder here, and in there just an
actions file. And for this entire file, I'm going to add userver at the top. So every function that I will be exporting
here is going to be a server action. So then I will just copy this so that will clean up the component itself. And I'm
just going to add that right here. I can remove it from the individual function. So I don't have to add userver to every
function here because it's already at the top of the page. I just need to import Prisma here. And we're going to
export it from here. So now I can use it in other parts of my application as well. Maybe I want to create a post in
in other parts. So this will run only on the server. I just have to use the name here. So um I just need to import it
here for the form. It will work the same way. So now if I go back here and I do fourth post number four. If I click on
create here, it's the data disappears here, but it did add it to the database because if I refresh, we can see number
four right here. If I want to see it here on the page, I do have to refresh. So it fetches the latest data again. And
indeed, we see fourth post. So this looks really strange um if you're not used to seeing server actions because
traditionally what you would do is if you had some form in the browser you would have to create an API endpoint on
your server you would do onsubmit so onsubmit then you would have to do some kind of fetch call right a post fetch
call you would first have to grab the data from the form and add it to that fetch call and then you would send it to
that post API endpoint that you would have a lot of work so now with server actions actually most of that is still
done behind the scenes but it's done for you. So if I actually inspect the network tab here, here we can see all
the network uh request. If I do fifth post, if I click on create here, you can see there is still a network request
here and it is actually a fetch call. If we click on that, we can see there is actually a fetch call to /posts and it
is actually a post request. And what is part of that post request going out from the browser here? Well, this is the
data. This is the payload. So you can see Nex.js s will automatically take that form data in this case our title
and content and it will submit it to our well it will send it you can think of it like this to this uh function here. So
we get the form data in here. So basically abstracting away the network boundary. So it is actually a very good
developer experience here to deal with updating data. Now so what it basically does it it automatically creates that
post API endpoint for you on your server side. So that means you should also treat it like one in terms of security
right. So you do want to do validation of the data here. If only uh admin users should be able to create new posts, you
want to do some authorization and authentication logic. So in terms of security and all of that, it's still the
same as a traditional API endpoint. In fact, you could technically also trigger these server actions to run outside of
the UI. So I'm just triggering it here by submitting a form, but technically somebody could send just a post request
to this particular URL and try to trigger the server action to run. So in terms of security, it's still the same.
It's just a better developer experience to deal with updating data. Right? So here we are creating a post, but you can
imagine that you also have a function for well perhaps deleting a post, editing a post or updating a post,
right? It it would all be uh functions like this that you can run in the places in your app where you want to run that.
And here I'm using a form. So forms they have an action attribute where I can specify the uh name of the server
action. But this works in other places as well. I don't have to use it in an action. Maybe I have a button, right?
And if somebody clicks on the button, we have on click. And if I want, I can also call it from there, right? So you can
run this. You can trigger the server action for wherever you want. Not only in forms, although forms are very common
because that's where you're actually submitting data. But maybe there is some icon here for deleting, right? So some
kind of cross. In that case, it maybe just it's just a button. If I click on that icon or button element, we want to
call the delete post, right? So that would be delete post that that would also work. Now notice when I create a
new post here and I click on create here the data disappears and we can see in our database that it does add it here to
our database. Yeah, that's good. But we don't see it in the UI here. I have to manually refresh here a page to
rerender, right? Meaning all the statements in here will run again including this getting the posts. This
is where it's getting the latest posts again, right? Number six included here. And so it will rerender new UI. So I
have to manually do that here as a user to see it. After refreshing I see number six here. If I try one more time seventh
post seven. If I click on create added to the database here number seven but I don't see it here in the UI here. But if
I refresh I see seventh post. This is not the best user experience we can get. So with server actions what I think is
really powerful is that after we update the data we can also trigger that page to rerender. So we can do that with
revalidate path and we can specify hey the /post route should be rerendered. So remember the browser will send a post
request when you submit a form with the server action. NextJS will send a post request to our back end and then right
in the response of that request it can bring the new UI after this has been rerendered as well. So really powerful.
So now if we do uh number eight if I now click on create here notice that the UI here updates almost immediately as well.
At least I don't have to refresh the page myself manually. The UI here updates in actually a very fast manner
here as well. So the mutations are reflected in the UI thanks to revalidate path. This is a very powerful function
because it can do it for the entire /ost route here. So the components on there will rerender including uh this page
component. We're going to get the latest posts. That's how it works. Now if you're doing other things on that route
as well that have nothing to do with this it would be a little bit too much maybe so you can get more fine grained
with that use cache directive right so we could also fetch the data in some utility function right so I can just
call it get post and the benefit is that I can now also use in other parts of my app if I want but basically we can use
the use cache directive if you have cache components enabled we can specify how long but we can tag it as well
basically give this cache a name I'm calling it post we've seen it before but now the benefit is I don't have to
revalidate a complete route, revalidate that particular tag. So there is revalidate tag which is and then which
one? Well, the posts one cuz I could have other data cached as well. And there is also update tag. So there are
some subtle differences between these two in terms of when it should exactly fetch the latest data. We'll discuss
that in a different video, but you can get more fine grain essentially with these tags. So those are server actions
in a nutshell. And the final thing here on the server that I want to discuss are these route handlers. So traditionally
you would actually create an API endpoint on your back end to deal with those type of to deal with those type of
mutations. And we can still do that. There are actually some reasons for that. There are certain downsides to the
server actions. For example, some people have complained that you cannot run these server actions in parallel. You
have to wait for them one by one. That's some subtle issues like that. So you may actually still want to have your own API
endpoints and in there interact with your database. But there are other use cases as well for these API endpoints.
You can imagine that you have uh Stripe or you have some kind of CMS or other services and they're going to send web
hooks when certain events occur. You can imagine in some kind of e-commerce application if somebody goes through a
Stripe checkout that is on Stripe's uh site usually. So we still want to be notified of course when somebody has
checked out. So Stripe is going to send you a web hook basically also a post request typically and that's typically
going to be sent to one of your API endpoint or imagine a CMS right so here in the post right so here in the blog
example typically there is a CMS for managing the actual content of the post so there may be editors and publishers
they work in some other environment basically a more dedicated environment for creating posts writing them editing
them when they have created a new post our app needs to be notified right because we need to display the new post
here or if there's some edit has been made maybe a title has changed we need to be notified of that so we can update
the app so the CMS may also send web host so this is where those route handlers come into play so they also
have some kind of URL so what you may want to have is something called / API well then you simply create a folder
called API just like any other folder and then well maybe something called posts so then it would be /appi/post and
instead of a page.tsx it would be a route.tsx tsx and in there we just export some functions and then you have
to use the name of the method that you want it to be. So for a post API endpoint you would have a function
called post. So you get the incoming request here and typically post is for creating a new post for example. So you
would grab the data from the incoming body and then we could use our Prisma ORM again to update our database, right?
You would send back perhaps the post that was created and on the same URL you may have other methods actually. So you
could also have getting data, right? So just your traditional request methods. So here if you would make a get call to
/ API/post, we are just going to return all of the posts here. In fact, let's try that out. So we can go to API/post
and here I get all the posts from my database because I have created the route handler the get API endpoint right
so we can actually try that here right so that's the URL that I created here with my folder structure all right so
that covers the server side for now and we talked a lot about it because NexJS well technically it's a full stack
framework but we do a lot of things on the server side so I would say it's even more of a backend framework than a
front-end framework but now let's talk a little bit more here about the client side. So here we have client components
right so so far all the react components that we've seen the page component right if we go here so the this posts page is
a server components all the components by default are server components right so also those other components that we
created the header component footer recently viewed those are all server components there's a bunch of benefits
to them and they run only on the server side so that means if there is something happening in the browser like there is a
click event or a change event right on change whenever you want to hook into those you cannot have a server component
for that so in that case you need to convert it into a client component so that's browser events but also if you
want to use react hooks like use state or use effect those all need to be in client component also if you want to use
the context API in react that's all on the client side so an example of that is let's say we want to add an upvote
button next to each of these uh links here we have that link here I want to add a button next to each one and it's
just a simple button and but when the user clicks on that we want to do something so here I do want to have on
click and we want to keep track of the votes for now let's say in use state so I want to have some kind of uh state for
the amount of votes right various standard react I'm going to display the number of votes in here as well so let's
create the use state here so you may think we can do something like this but as you'll see if I now go back we get
into an issue here because I'm trying to use state use state in a server component this posts page is the server
component. So this is not going to work. So this will only work in a client component. Now you may think we just
have to convert this into a client component. So you can do that with the use client directive. But when I do
that, we lose all of the other benefits that we get from server component. So one of those benefits is actually using
our OM to interact with our database. Right? So now you can see I already get warnings about that. But basically, we
do not want to turn the entire component here into a client component just for that little button because everything
else in this page component can remain on the server. It's just for that little button component on the page that we
want to have a client component for. So basically, when you're creating client components, you only want to do it for
that specific component that actually needs it. you actually want to keep things on the server and you want to be
very precise with what part should be a client component. So the solution is typically to create a separate component
for this. So instead of doing all of this here in the posts page component, we're going to create a separate
component for this. So here I will go to components. I will call this upload btn create a component here. And I will just
copy all of this markup and paste it right here. And I can create the react state here as well. So now I can just
use this component instead. So now I can go here, I can import this. So now I still have my upload button here and
everything else here can stay on the server side. So this component will remain a server component. We can still
do data fetching from our we can still use our Prisma OAM to get data from our database and all the other benefits we
get from server components. But then for this little component here, this little piece on the page where we do need to
hook into well browser events or where we do want to use react hooks specific piece is going to be turned into a
client component. So here I'm going to add use client to the top. Now if I go back you can see I don't get any errors.
And if I click on it all of this works, right? So I can upote now and have all of this work without losing all of the
benefits from server components. Right? So all of this what you see here are server components but just this well you
could say little island of interactivity. Just that little piece is what we're going to turn into a client
component. That is typically how you want to solve that issue. You can also trigger the server actions from client
component. Maybe we do want to keep track of it in our database. So we basically just have the server action
that will run only on the server side that will update our database. Basically increment a posts uh upotes by one. So
we just have to trigger this from somewhere in our app. So here in the upload button component on click instead
of incrementing this low instead of incrementing some react state we just need to call that upvote post uh server
action. So here if I click on second post upvote we can see it actually increments here. If I check out the
database you can see that the second post now has one uh upvote here. If I keep clicking a few times I have six now
here. If I refresh my database you can see it's also reflected here in the database. So I have a client component
and we used it in a server component that posts page. That's not a problem. So we can have client components in a
server component and I can also import other components in here. For example, maybe I have an icon component, right?
So just icon. The only thing it shows is icon here. Maybe I'm using that here somewhere. Maybe I'm just using it here.
I'm importing it into this file though. Now I have icon here. Okay. Now this icon component is actually also a client
component now because I'm importing it into a client component even though it does not have use client itself at the
top here because I'm importing it here it becomes a client component here. Basically this use client is more of a a
line like a boundary. So after this whatever you import will become part of that client side boundary. Right? So
actually if I would import other things into this file here, those would also be part of that client side bundle. Right?
So this is more like a demark right. So basically just marking the boundary here of what should be on the client side.
Right? So that is how it works with client components. All right. Now one little advanced thing here. Don't worry
if you're confused. What happens if we run a build here? So we're using this client component here on the slost
route. So we can see that when we run a build, the slash post route is still statically rendered, right? So we're
basically creating HTML out of slashpost. So that when somebody goes there, it's very fast. Everything is
already pre-rendered. So this works even if there is a client component, right? So that may be a little bit confusing
because you may think, well, we have a client component on the page, that page cannot be rendered on the server side,
right? When we pre-render it here in the build, basically it's run on the server side. So this is a little bit confusing
but basically the way to think of it is server components run only on the server. Client components run mostly in
the browser but they can also run on the server particularly during pre-rendering during the build in so initially when we
statically render some route if there's a client component on that route there's no problem the client component will
still render this button will still be part of the HTML right and then later once the app is actually active in the
browser it's running only in the browser right so that's a little bit tricky but bit more advanced don't worry if you're
confused I have other videos on this. We're almost finished here. There are a few last things that you need to know
about as well. So, at some point, we want to deploy our app and have other people actually come and visit it. So,
there are a couple of different ways that you can deploy an XJS application. So, what I show you before is that we
could run npm run build ourselves and it would create an optimized version of the app, but typically people will deploy it
to a managed platform like fcell. FEL is really popular uh hosting solution for nextjs apps. V 0 is also using Nex.js. A
lot of these platforms are using Nex.js and very often in those scenarios it's deployed as a NodeJS server meaning all
of the features are supported. So there is a server running in the background or or very often also serverless functions.
So there may not literally be a longunning server in the background but there are server side resources
available for the app. Okay. So you don't really need to do anything to enable that. uh these managed platforms
have made it a really easy experience to deploy. The other option is you could Dockerize the Nex.js application and I
have some videos on that on my YouTube channel and then you can deploy well wherever docker is supported. So we've
done it a few times to a VPS. I've used Hostinger for that. The benefit of this is it can be a little bit cheaper than a
managed platform but of course you you do need to do a little bit more configuration yourself. It's not as
handsoff so you need to be a little bit more techsavvy but all the features should be supported. So you should be
able to run all of these backend features as well. You can actually also do a static export of Nex.js. Basically
when you run a build it will create a bunch of HTML, CSS and JavaScript files. You can put those on a CDN for example
and well have a basic website or even like a a spa or a single page application very similar to like what
you had before in plain reactive vap for example. In that case though you do not have all the features supported right.
So in that case you cannot have server actions or route handlers because there's not going to be a backend uh
servicing requests. It's just going to be a bunch of static files. So those are the common ways to deploy next.js but I
have other videos on my channel if you want to go more in depth. Now there is also something called a proxy here in
Nex.js. So when there is an incoming request to the server side it can go through a proxy. This used to be called
middleware. So you can imagine that um we want to do something on incoming requests before we do anything else on
our server before it hits any of our server actions for example or API endpoints or whatever anything on the
server we may want to do something with the incoming request first. We may want to modify something about the incoming
request. We may want to rewrite the URL. Maybe you want to do some AB testing on different requests. So for those types
of quick modifications essentially of the incoming request you can use a proxy for that. So let me quickly show you
what that would look like. So here in the project root we can create a file called proxy.ts or if you're using the
source folder it should be in the root of the source folder. So from there we export a function called proxy. So here
we get the incoming request. We can do something with that. For example we can check the URL that the user is
requesting and we may want to redirect them. So we can simply say nope we're always going to redirect to /home. So
this proxy runs not on every incoming request only on the ones that we configure here. So we have a matcher
here. So right now this would only work for slashabout/ something else. So you need to pay some attention here to the
matcher. So they showed an example in the documentation for if you typically want to match well a lot of things. Not
necessarily everything though because very often we do not necessarily want to do anything if it's a request for a
static file like /logo.png. We don't need to do anything in that case. is we do not want to redirect the
user for example right or like so for particular image things or API routes we may want to skip right so this is not
literally matching everything but still a ton of requests that the user is going to make so now if I try to go / post I'm
redirected here to /home of course I do not have any homepage so we're going to see that if I just make it the homepage
we're going to be directed to the homepage so if I do post we go to the homepage but notice that we actually get
an issue here because when I go to the homepage that's a new request we are again getting an incoming request and
again redirecting. So you get in sort of like a loop here. So you do need to be mindful of how this works. We can have a
guard here. So we only want to do this if they try to go to posts or let's say they want to try to access the admin
area, right? So this is an example perhaps some optimistic redirect and in case uh they're trying to access
something that they aren't authorized to access. So else we can just allow it to continue. Right. So we can also call
next so they can continue. Right? Right. So then the request would go through the proxy to whatever they were trying to
access on the server. So now if I try to go to the admin area, I'm being redirected here to the homepage. Okay.
So this could be like your first line of defense when it comes to authentication or authorization. So what are the common
things you want to do here? Well, according to the NexJS documentation, the common scenarios are things like
modifying headers for some pages or rewriting to different pages depending on AB tests or experiments or redirects
based on incoming request properties. So, mostly very quick uh rewriting or redirecting type of situations. Now,
what about authentication? Because here we are already doing some kind of authentication or authorization, right?
Maybe depending on the user's role, they should be able to access it or not. So I would mark it as a question mark here. I
think there are some use cases for authentication and authorization in here particularly like an optimistic
redirect. And actually also because of how static rendering works with um checking the the cookies for a JSON web
token for example if you do the check on a page it's going to be opted out of static rendering as we've seen. However,
if you do the check in proxy that page can remain statically rendered. So if you have static pages behind an
authentication, it actually may be a use case to explore here to do the authentication check in here. But
typically what you want to avoid here is doing a lot of computation intensive work or doing IO type of requests,
right? So making a network call to your database for example or API calls to some other external API because this is
more meant for these types of quick uh rewriting redirecting type of scenarios. So authentication or authorization, I
would say it's a question mark. There are some subtle scenarios and I have other videos on that. It's too much to
explore in this one. In the documentation, they do mention these optimistic checks. So they do mention
since proxy can run on every route, it's a good way to centralize redirect logic and prefilter unauthorized users or to
protect static route for example content behind a payw wall. But they also mentioned it's important to only read
the session from the cookie an optimistic check and avoid database check. Right? So if you have a database
session strategy for authentication, this is probably not what you want to do. However, if you're using JSON web
tokens and you can just read the incoming token and based on that you can redirect the user. I think that makes
more sense. So here they have an example. We can check if the incoming request is for a protected route. Then
we grab the cookie. We grab the information about the session from the cookie. And then if it's a protected
route and the user does not have the the right credentials, we just redirect. And we may want to exclude some routes here.
So let's actually talk a little bit more about authentication. Let's say the post maybe we only want this to be available
for paying subscribers. Before we even get to payments, we first need to make sure that only logged in users can
access these these posts. And then also for creating a new post, right, we only want authenticated users to be able to
create new post. So how would we even go about doing that? Well, authentication basically works by checking the user's
cookies and seeing if they have a valid access token. So, this is typically JSON web token and there are other
strategies, but this is a very common one. So, if I go into my own cookies here and check for this domain local
host 3000, I do not have any access token. So, we could manually set up a whole system ourselves where we create
the tokens and verify the tokens and basically do it ourselves. This is something you could do, but there are
also third party solutions for authentication that have honed in on this already and have made it a really
good experience actually adding authentication to your product. So, I've really enjoyed using Kind. I'm a brand
ambassador for them and that's what I would use to authenticate my NextJS app. But the underlying fundamentals remain
the same. So, with Kind, a user is also going to get some kind of access token and then we're going to check before
they try to access something if they have a valid token. So the underlying fundamentals remain the same and also in
terms of how we should do the checks also remains the same. So I'm going to show you how to do it here with kind.
It's very fast and easy. But even if you're going to use some other solution, it's going to be very similar. If you
want to follow along with that, make sure to use my link in the description by the way. So here in kind, I can have
a lot of applications protected with kind. So first we have to create a new application. I can call this next blog.
And nextjs is more of a backend framework. So I'm going to pick backend web here. And here we can pick nextjs
and click on save. And here it will show you how to set it up. So we already have an app. So I can click on existing
codebase. We can set the call back URLs here. And then I just install this package. So I just run this in my
terminal. Next we need to add environment variables. So actually we haven't use this yet but in XJS it's
very commonly done with.lo. So make sure you don't show the secrets to other people for example. And you can
see it's grayed out because it's part of the git ignore. In older versions I believe.loc local was not automatically
included in g ignore. So, so if you happen to use an older version, make sure you double check. But you can see
here it's also grayed out and indeed it's opted out of it. Then we need to create some uh route handlers actually.
So this is what kind will use uh internally by itself to verify if a user is authenticated. So they do use the
source folder here in the path they suggest. I'm not using a source folder here. In the latest NexJS by default uh
with the default you don't get a source folder. So I will just copy it from the app folder onward. So actually here in
VS code I can actually just create a new file here in the root and just paste that entire path and it should put it in
the right uh structure here. So here now I have route.js and I can just copy this and paste this right here. So this will
just internally wire up a get API endpoint. And now we have some options here for login link and register link.
So let's actually add those to our header. These are just some components. So I will just I will just add that
right here. And actually I will copy this path where they are importing it. It's just make sure it's importing it
from the right package. Okay. So now I have the components. Now if I go to my homepage I can see I have sign in and
sign up. Of course we can style it a little bit better but let's not waste time on that. Let's say I want to sign
up. So now if I click here you will see that I'm going to be redirected to a kind managed uh login page or register
page. You can see this is on kind.com. So I don't have to create these whole authentication screens. I don't have to
worry about this whole flow. This is all managed by kind. And we can actually also uh customize this in terms of the
options I have and also in terms of design and styling. But for now, let's go here to authentication. Here we can
decide how users should be able to authenticate themselves. So email and code. I actually like enabling some
social connections like GitHub as well. So let's actually enable GitHub. So now if I refresh here, we also see the
GitHub option. So I'm going to register here with GitHub. All right. And after that, I'm actually being uh redirected
here to /dashboard. This is very common especially in a like a dashboard type of app, right? But now we have a blog site.
So actually here in the environments variable we have login redirect URL. I'm just going to put it I'm just going to
change it to the homepage instead. Okay, but I'm logged in now. I've created an account and automatically I'm logged in.
How do I know that? Well, if I go to application here and now I go to my cookies, I can see that I now have this
access token. Right? So this string here is what will allow me to access protected resources. If I have it, I'm
logged in. If I don't have it, I'm not logged in. Right? That's basically how it works. So I can go to /hosts now.
Well, actually everybody can still go there. So we are not protecting it. So let me actually also add a log out link.
So we can actually toggle between that. So I will add a sign out here as well. So now I have sign out. If I click that
and now I go back to my tokens. So you can see I have no access token anymore. because I'm logged out now. So I should
not be able to access /posts. However, I'm still able to access it. So we need to protect it. So here we have the posts
page. I do not want unauthenticated users to be able to see the post. So before we even do anything with our
database there, I'm going to have an authentication check. Now kind has a function that you can use anywhere on
the server side and this is a server component. So I can do this function. It will check from the incoming request if
the user is authenticated. Basically has that access token. So before we continue, we can just check if the user
is not authenticated. So I do have to use the await here and negate it. I could well I could instead render
something like please log in or something like that. But typically we just want to redirect. So there is
actually a redirect function here in nextJS as well. This is just nextJS and we can actually just redirect to that
actually the API endpoint that kind offers which will then automatically show the uh login screens that kind
offers. So the redirect function you just coming from nextJS itself. We actually do not need to add return here
and that's because this function works a little bit differently. It will actually throw an error behind the scene. So it
will just error out here. It will not continue. However, I still like to add it here just uh to be sure, I guess,
just for just to make it easier to read. And actually, this should be slash login. And actually for more advanced
pattern where we actually automatically want to redirect them to the URL they were trying to visit, we can append
other information here, right? So this can be pretty. So this can be more advanced, but we're now just redirecting
them to the login screen here with kind. So I'm logged out. Now if I try to go to /ost, you can see I'm not seeing the
posts here. I'm being redirected to the login page here, managed by kind. So now I can continue with GitHub and I already
have an account. So I should be redirected to the homepage first. So now indeed I'm here at the homepage. Now if
I want to see the posts, I can go here and indeed I have access to the posts again. Right. Very quick way to add
authentication to my Nex.js JS. So here I'm protecting this particular uh component, right? So in this in our
scenario that's fine because we're only doing data fetching uh like this in this particular component. So in this case
that is indeed what we want. Now what if I'm also fetching posts in some other part of my app? Maybe on the homepage
we're displaying the top 10 most uh viewed posts or something like that. Right? I'm not protecting the homepage
right now. So typically actually it's more important that we protect the data instead of a particular component or a
particular view. It's more about protecting data. The data is more important than the UI. So typically we
want to couple the authentication check with the data fetching or data updates. All right. So here we are checking in a
server component, right? We're getting data. But remember what I told you about server actions. These are basically post
API endpoints on your server. They should be treated the same including with authentication. So if we only want
to allow uh logged in users to create posts, I need to add the authentication check in the server action as well
before we try to do anything with our data here. Right? And the same goes for the other server action. A more robust
approach to authentication is with something called a data access layer where we couple the authentication check
directly with the data access. So here we have just written it uh closely to each other. But there is a more robust
way to go about doing this. I have other videos on that. Check out the data access layer video. And we can get way
more advanced with kind. There's all these other ways to let users authenticate themselves. We can
customize the tokens as well. If you want to add more information to them here, you can add things to the tokens.
Kind also allows us to very easily add roles and permissions. So if you want to add something like arback authentication
to your app, very easy to do that here as well. We get a really nice overview here of our users that we have in our
app. And it can get way more advanced. uh you can do all sorts of B2B or even marketplaces types of apps. It's not
just a simple use case like what we have here. It can get way more advanced and actually they also have billing. Now
billing is actually quite closely related to authentication because we basically also gate access based on some
user property. So it's actually very nice to have that come out of the box here with kind as well. And actually
there's way more. So there is also design here. I can customize that uh login page that you saw, make it look
more like my own brand. We can change the page content here, right? So we can have all of these pages here. We can
customize the content, even add custom code. So we can customize a lot of this and actually with customization you can
make it more advanced even they have workflows as well for more automation type of scenarios. So I'd say check out
kind with a link in the description. So that is modern XJS in a nutshell. Well done for making it all the way to the
end. If you're a little bit confused about some things, it's totally normal. It is in all honesty sometimes a little
bit complex and there are some nuanced uh scenarios where you really need to understand how it works and just using
your AI coding agent is not going to be sufficient. You really need to understand what's happening under the
hood. So I hope with this video you have a better sense of what those things are. In any case I want to thank you for
watching. Make sure to check out Kind. This video would not have been possible without them. So really thanks to them
and you can find a link in the description. And of course check out my other videos on my channels. I have so
many other videos on NextJS also more advanced videos. So, thank you for watching and I hope to see you in the
next one.
Next.js is a full-stack framework with both client-side and server-side execution. Unlike Vite-based React apps, Next.js allows you to handle database operations, API keys, and heavy computations directly on the server within the same application, making it more powerful for building complete web apps.
Server components are the default and run only on the server, making them ideal for data fetching from databases or APIs. Client components require the "use client" directive and handle browser events like clicks, state, and effects. The best practice is to create small "islands of interactivity" with client components while keeping most of your UI in server components for performance.
Server Actions are functions that run only on the server but can be triggered from the browser using the "use server" directive. They are perfect for creating, updating, or deleting data (CRUD) without needing manual API endpoints—Next.js creates them automatically. You can combine them with revalidatePath() or revalidateTag() to update the UI after mutations.
use cache provides granular caching for specific data fetching functions rather than whole routes. You set expiration with cacheLife and can tag caches to revalidate them on demand with revalidateTag(). It offers a cleaner API compared to older fetch-based caching, giving you more control over performance.
PPR combines static and dynamic content by pre-rendering a static shell and streaming dynamic parts (like user-specific data) later. Enable it with experimental.cacheComponents: true in next.config, and wrap dynamic components with <Suspense> for streaming. It's ideal for pages where most content is static but some parts need real-time updates.
The proxy.ts file in your project root is used for quick modifications on incoming requests, such as redirects, rewrites, or A/B testing. It replaces older middleware for tasks like optimistic authentication checks with cookies, but it's not suited for heavy computation or database calls—keep those in server components or actions.
To use Kinde authentication, create a Kinde application and install its package, then add environment variables to .env.local. Create route handlers for Kinde's callback URLs, protect server components with getKindeServerSession(), and also secure server actions and data access layers. This provides robust authentication without manually building auth logic.
Keep this summary
Save it to LunaNotes and it becomes a real note in your library — editable, searchable, and ready to turn into flashcards or a diagram. Free to start.
Save to LunaNotesOr summarise for another video.
This summary and transcript were automatically generated using AI with the Free YouTube Transcript Summary Tool by LunaNotes.
Related summaries
Build a Modern Frontend Developer Portfolio Using Next.js, Tailwind CSS, and Sentry
Learn to create a stunning developer portfolio with animations, responsive layout, and performance tracking.
Implementing Your Own Design System in Next.js
Learn how to efficiently create a reusable design system in Next.js using Tailwind CSS and other modern tools.
Understanding Backend Architecture: How Requests Travel and Why Backends Matter
This comprehensive summary explains the fundamental concepts of backend servers, tracing the journey of a web request from a browser to a server deployed on AWS, including DNS resolution, firewall filtering, reverse proxy configuration, and node server processing. It also contrasts backend and frontend roles, highlighting security, performance, and architectural reasons why backend logic cannot be fully executed in frontend environments.
Essential Nuxt Modules for Optimizing Your Next.js Project
Discover the must-have Nuxt modules for linting, testing, SEO optimization, and more to enhance your project.
Comprehensive Full-Stack Developer Course Overview & Learning Strategy
Explore an extensive full-stack developer learning path covering HTML, CSS, JavaScript, React, TypeScript, Node.js, APIs, AI integration, and Next.js. This course emphasizes hands-on projects progressing from foundational concepts to advanced AI engineering and full-stack application development.
Most viewed summaries
A Comprehensive Guide to Using Stable Diffusion Forge UI
Explore the Stable Diffusion Forge UI, customizable settings, models, and more to enhance your image generation experience.
Kolonyalismo at Imperyalismo: Ang Kasaysayan ng Pagsakop sa Pilipinas
Tuklasin ang kasaysayan ng kolonyalismo at imperyalismo sa Pilipinas sa pamamagitan ni Ferdinand Magellan.
Mastering Inpainting with Stable Diffusion: Fix Mistakes and Enhance Your Images
Learn to fix mistakes and enhance images with Stable Diffusion's inpainting features effectively.
Pamamaraan at Patakarang Kolonyal ng mga Espanyol sa Pilipinas
Tuklasin ang mga pamamaraan at patakaran ng mga Espanyol sa Pilipinas, at ang epekto nito sa mga Pilipino.
How to Install and Configure Forge: A New Stable Diffusion Web UI
Learn to install and configure the new Forge web UI for Stable Diffusion, with tips on models and settings.
Found this summary useful?
Take it with you. One click puts it in your own LunaNotes library.
Save to LunaNotes