So now let's go ahead and explain the project structure a bit more and let's talk about the routing inside of Next.js. So first things first it's quite important to understand the top-level folders which are available which is the app folder, pages folder, public folder and the source folder. In our project we only have the app folder and the public folder. So we don't have the source folder because once we initialize the application I told you to select no for the source option so all that we do is be additional or optional application source folder but I have no preference around that so I don't use it inside of my projects. The next one is the app folder.
The app folder is where we're gonna have all of our routing system, our React server components, our interactive components, basically everything that needs to be rendered under a specific route or a layout. Whereas this components folder is our custom named folder. You can see that that is not reserved, it's not specifically recognized in Next.js as something special. This is our convention which was made by ShatCNUI once we added the button using the npx-shatcnui-add-button command. Great.
And the pages folder are the old way of routing in Next.js. So if you ever used Next.js in the past, you've probably used the pages folder. That has changed and today the default is the app folder. That being said, if for any reason you still want to, you can always create the pages folder on the same level as app folder and then work as you are used to but keep in mind that you're not gonna have server components inside of that. Great, so we covered top level folders now let's talk about top level files.
So we only have a few of those here. We have nextconfig.js right here, which you can see is completely empty for us. In here you can, for example, extend webpack if you need that. Then we have package.json, which you're probably familiar with. In here you can see all of our scripts and dependencies which we have installed inside of our project.
We're also going to have a middleware file but we're going to do that later. Middleware can be used to intercept every single route and decide whether to block a user from showing that route so it can be used for authentication or it can also be used to detect bots and IP addresses and block someone from your website. Then we have your usual .environment files we're also going to be using those. SLint configuration, gitignore, basically all of the configuration files and you can read more about what they mean here. And now let's talk about the routing conventions.
So how did I know that in order to change this page I needed to go inside of the app folder and specifically go inside of page.psx. That's because I know the app router routing conventions. So I know that every file which is named page and ends in any of these extensions right here represents the page. And I also know that every layout represents the layout and you can see all different Reserved file names inside of the app router So layout page loading not found error global error a route template and default Using this project. We are only going to be working with the layout and page and perhaps loading and error we're not going to be using the other ones.
And the route is simply used if you want to create API endpoints. And we are actually gonna have one route my apologies. Right so how do we actually create a new route right we know that it's page.tsx but where do we put that? Well here's an example of nested routes right if you create a new folder and then inside put a convention page.tsx that folder is going to become a new route. So let's try that out.
Inside of the app folder I'm gonna create a new one called test and then inside a new file page.tsx and here's what important every time you create a page.psx. It needs to export default. So make sure that when you write something like page and return a div saying hello test page You need to make sure that you write export default page otherwise it's not gonna be registered as a route. So this is my structure. Inside of the app folder I have a new folder called test and inside of it page.psx.
What I can do now is go to localhost 3000 slash test and there we go we have hello test page and you can try and comment out the export default and you can see how it's immediately going to break the page and give us an error. Great! So we know how to create a very simple route now and here's an example of how to create a nested route. So let's try that out. Inside of the test folder create a new folder called subroute and inside of it let's go ahead and create a new file page.tsx and let's do the exact same thing.
Const page and let's return a div subroute page and let's export default page. And you've probably noticed the name of the component you are exporting does not matter. It can be named whatever you want. All that matters is that you do a default export. What does matter is the file name and the folder name.
The folder name can be whatever you want, but keep in mind that that's gonna be the exact URL inside of your application. So make sure that inside of the test folder you have another folder whatever you called it and did a default export and then I'm going to go on localhost 3000 slash test slash subroute and there we go You can see that now I'm on the sub-route page. Great! And in here we have some additional types of folders and routes like dynamic route segment. This will represent something that is not hard-coded.
For example, a user ID. Let's check that out. So I'm gonna go ahead inside of the app folder and I'm gonna create a new one inside of curly brackets. I'm gonna write user ID like that and perhaps it's better that we actually create users first and then let's drag and drop user id inside of the users like that. So make sure you have app folder, users, user id and then inside let's create a page.tsx right here.
Now in here we're going to have something special. We're going to have an interface user id page. It doesn't matter, it can be named whatever you want and in here we have access to the params and I know that inside I'm gonna have a user ID which is a type of string so how do I know that I have user ID here because that's how I named the variable inside of my square brackets. That's why naming is important. And now what you can do is write const page.
Let's go ahead and extract the params. And let's assign the types here. User ID page props. And in here, let's just not misspell this let's return a div user ID and let's write params dot user ID like that. So let's take a look at our routes.
Inside of the app folder I have users and then I have user ID and inside of it I have page.tsx. What I can do now is go to localhost 3000 users 1234 and let's go ahead and export default. So there we go I forgot to do that. Always make sure that whenever you are creating a new route you add a default export. I forgot to do that my apologies and there we go.
You can see that now we have a user id which exactly matches what we have inside of our URL. Perfect! And you can also do a catch all route segment or optional catch all route segment. And now here's an important thing that you also have to understand. Folders are not always necessarily, don't always necessarily have to be used for routing right sometimes we just want to create a folder to organize something and we can do that using this convention by adding parentheses This will group routes without affecting the routing.
But that is different from adding an underscore. This will completely opt folder and all child segments out of routing. So what is the difference between those two? Let's go ahead and quickly explain. So Let's go ahead and create two examples in here.
So inside of my app folder, right now, if I want to access the subroute, I have to go through test, like this. So I have to write slash test slash subroute. That is the only way I can access this. But here's an alternative way you can do that. So I'm going to remove the test folder entirely and all of its children and now this will be a 404 page.
What I can do is I can wrap test inside of parentheses like this and then create a new folder subroute and then inside create page.dsx let's create a const page return and I'm gonna write rendered at slash subroute and let's not forget to add expert default page and how do you think we access this subroute now? Let's take a look at what this says. If something is wrapped inside of parentheses, group routes without affecting the routing. But that doesn't mean that the children are not affected. So all that we did here is we changed this parent folder to not be used as a part of the URL.
Instead it's just a useful folder if we want to organize some things together. Because when it comes to file and folder based routing, when it comes to a very big project it can get quite haptic. So now what we can do is simply go to localhost 3000 slash subroute. And there we go rendered at slash subroute because we are completely omitting this parent folder right here. And what is the difference between this one you might ask?
Well that one is quite simple That will completely remove everything. So I'm going to remove this folder and I'm going to create a new one, underscore test and then inside I'm going to create a normal route like this, page.tsx. Let's go ahead and export page. Div I am never rendered. So this is my folder structure.
App folder underscore test subroute page dot dsx. Very similar to the last two examples we had, but this time the parent route has an underscore. So let's see what happens if I refresh here. Slash subroute is a 404. How about slash test slash subroute?
That is a 404 as well. How about slash underscore test slash subroute? That is a 404 as well. So whenever you see me using the underscore which I will most likely use for some internal components which are not reused throughout the project it means that I am purposely doing that. So that is in my opinion the best way to hold components inside of the app folder.
Because otherwise, let's say that you have a components folder inside of here and you accidentally create a page component like this. For example, like this. You know what you mean by this. You don't expect this to be a page, right? But since this is a default export, so I just copied and pasted from here if you're confused.
Inside of my components here I've pasted this and if I go to localhost 3000 slash components now this is all of a sudden a file route. Well, that's not what we expected. Most likely if we have a folder named components, that's why I recommend that you hold your components in underscore components. And you can see how that immediately turned this into a 404 page. And you can still import from this folder in all your other routes.
So it's not like they don't exist. They are just omitted from the actual routing system. And every now and then if you play around with these existing routes and change one from an underscore then to a route group with parentheses then to a dynamic one you're often going to see this one unsaved file pop up which is located inside of this .next cache. That is very simple to fix. You can either go directly inside and click save but if you think you've messed it up for any reason you can very easily resolve it.
So first go ahead inside of your terminal and shut down your app and then go ahead and remove .next entirely. Like that. And here's where the magic happens. All you have to do is npm run dev and that is automatically going to generate a new dot next folder. So don't worry, you cannot mess that up.
It can happen when during, you know, hot reloading and actual development, you change the type of your folders it probably confuses Next.js a little bit so that cache happens. Great and just one more thing that I want to cover is the layout file because yes we have some more like parallel and intercepted routes. I'm not gonna talk about them in this tutorial. I'm gonna reserve that for something else. But I do wanna talk about layout file because that's another file that I'm gonna be using inside of this project.
So that one is quite simple. Let's take a look at an example that we have. So inside of this users folder, right now I can go to slash users, slash one two three four five six, right? There we go, so that is working normally. So now let's go ahead and inside of this users folder let's add a separate page.tsx.
So now both my users folder has its own page but also user id has its own page and in here I'm very simply going to export a page saying div user list. So now I can go to localhost 3000 slash users and there we go now I have a user list. So how does layout work in here? How are layouts useful? Well let's say that I want to have a specific navbar whenever a user is visiting the entire user's route group.
I don't care if they are in the specific user ID page or on the user list, or even down further, if I create more sub routes like specific user settings, I always want them to have a specific navbar. Well, layout is a perfect file to put that. So we don't have to copy and paste that navbar component every single time. So inside of your most top level route group or I mean you will know where you want that of course but this is just for an example. Inside of the users here alongside page.tsx we're gonna create a layout.tsx file and this one will immediately gonna throw you an error because we need to export default the same way we do with the page folder.
So let's go ahead and write const layout. Again, the name doesn't matter here. And let's just return I am a layout. Ignore that typo of course and let's export default layout. And there we go.
Now it says I am a layout, but where is our content? Where is the user list? And if I go to slash user slash 123, where is the user ID? We cannot see either of those. Well that's because layouts work a bit differently.
Every time you use a layout, you need to export the children. So let's create an interface, layout props here, children, react, react node. And in here all you have to do is assign those layout props and you can extract the children and then inside of this div simply render the children and there we go. Now our pages work exactly as they used to work before. So I can see the user list on slash users and I can see the exact user id here.
Perfect! And here's where the magic happens. Go inside of your layout.dsx let's go ahead and give this a class name of flex-flex-col-gap-y-4 so we are going to order these elements one below another with a gap of 4 between them which is 16 pixels and in here I'm going to add a little navbar element which is going to say I am a reusable navbar and in here I'm going to give it a class name of text extra small padding of 1 bg red 500 and text white I think that is more than enough. And here's the cool thing. This layout is reflecting every single page inside of users.
So currently I'm on user ID But if I go back to slash users, you can see that this is right here and here's the cool thing. This is not re-rendering. So that's why this layout files are so powerful. Whenever you want to create a sidebar or a navbar, layout is the perfect place to put that because then all of the other content which is changed by your routing will only be rendered inside of this part right here and the actual layout like the sidebar or the navbar are never gonna be touched except if there is a refresh in a server component inside of themselves but we're gonna talk about server components when we encounter them first. Great, I hope this kind of cleared it up and here's what I'm gonna do just to wrap this up I'm gonna delete everything here just because I want you to be on a blank slate here so we don't need the components, the test or the users.
Like that. So we just need page.tsx and go back to localhost 3000 and you should have the click me button. And just to explain, this layout is different from the one that I just told you because this is a root layout. You need to have this file. You can see that this one is quite important because it renders the HTML and the body.
But other than that, it functions exactly the same as our layout from the users. Great, great job!