Now let's talk about Next.js project structure. So I highly recommend that you visit the documentation yourself. Just make sure that in the documentation you select the app router option. So don't select the pages router. That is the old version of Next.js.
So let's go ahead and learn the most important things about project structure in Next.js. So first of all, we have two types of routing conventions. One is the app and one is the pages folder. So that's what they mean when they say app router. It basically means that you have the app folder inside of your project.
In previous versions of Next.js there was the pages folder which was also used for routing but it worked slightly differently and in PagesRouter all components in Pages were client by default but in the AppRouter all components in Pages are server by default And if you don't know what that means, don't worry. We're gonna get familiar with that as well. So first of all, here are some top level folders for you to understand here. So the app represents the app router. The pages represents the pages router.
And yes, you can have both in one project, right? But more usually than not you're not gonna do that. So the reason they allow you to have both the app and the pages router inside of your project, for example this is our structure, right? We have the source so this picture represents it better. The reason they allow you to have both app and pages is because of the migration process, right?
So changing from the pages router to the app router was a very big change that Next.js made and introduced server components and all of those things. So finally they decided they're gonna allow you to do both. So you can incrementally create new stuff in the app router and slowly migrate from the pages. And of course we have the public folder, which is where our static assets are going to be served like some hard-coded logos or stuff like that and we have the source which is the optional source folder right so there's a reason why I chose to have source folder in this project right here and it's actually because of the Tailwind config right here so you can I don't know if you know if you've ever set up Tailwind yourself, right? We did this a lot in my previous projects, for example, my Netflix clone and my Twitter clone.
At the time, Next.js did not have the option to initialize with Tailwind. So what we had to do was we had to set this up ourselves. So back then, you know, I kind of knew exactly which one of my folders actually have Tailwind inside of them, because by default, Tailwind will not be available anywhere in our project besides these folders right here, these paths. So it's just easy to use the source folder because then I know, okay, anything that's inside of my source folder will have Tailwind. So if I want to create a new folder here called features, which is something that we're going to have later, I don't have to worry whether this folder will be supported by Tailwind or not.
That's something I forgot to do in my last tutorial, which was the finance manager, right? So I actually added an additional chapter in my last course to fix that. So this time I'm fixing it from the front by using the source directory. So that's what the source directory is for. It's completely optional, right?
You don't need it, but let's see, I actually find it quite useful. Then we have some top level files, which are the ones you're seeing right here, which are outside of any folders. So the next config, which is obviously the configuration, the package json, which holds our packages and our scripts or maybe more precisely our dependencies and dev dependencies here and we're gonna work with some scripts here later. Then you have some specific Max.js files like instrumentation.js which I personally have not yet used and we are not going to be using this in this project. We have the middleware which is kind of a sketchy subject so it's a great solution to a problem.
My issue with it is that it only works well on the edge, which kind of means that we are limited to what we are going to use it for. So I'm actually going to try to avoid using it in this tutorial because I want you to be able to use this project and deploy it anywhere. I don't want you to only be able to deploy to Vercel. I want you to be able to use this project on your personal VPS, on fly.io, on a railway, wherever you want. So that's why I'm not gonna be relying too much on this edge stuff.
And of course we have some .environment, .environment local. We actually don't have this at the moment, but we will have them later when we add our first environment dependent packages. We have the slint file which is the configuration for slint which kind of emphasizes the rules of our code and we have the gitignore. So gitignore simply tells us what will not be committed to git. What's important here is that you have this .environment.local At least that.
I actually don't care about anything else but the most important thing is that you never ever ever commit your environment files Great, and then we have some additional configuration for TypeScript, for JavaScript and stuff like that. Great! And now let's finally talk about the app routing conventions right here. So I think it's best to learn that through actually writing something. So just make sure you have your app running.
So first things first. Let me just close this now. So inside of here, you have already seen that in the app folder, we have these two. We have the layout and we have the page. And let me click on the layout so that maybe it can explain it better through documentation.
So a layout is a UI that is shared between routes. And a root layout, which what you're seeing right here is the topmost layout in the root app directory. And this layout specifically is used to define the HTML and the body tags that are other globally shared UI. So this root layout file is not something you can remove because it gives your app the necessary HTML body and close tags right here, right? And it also initializes some metadata.
So this metadata is reserved constant in Next.js layout and page files, right? So whenever you write this in a layout file or a page file it will actually change the metadata as you would add as if you were adding these in the head tag in the most basic HTML type of coding. So this is the root layout which you cannot delete. You can modify it but you absolutely need it for the project. Later on we're gonna have our custom layouts.
For example take a look at this route. App folder, then some random dashboard folder and then a layout file inside. And you can see how it's much simpler than ours. So we're gonna have to use... We don't have to but it is very useful for us to use this because one cool thing about this layout is not only that you can use it to re-share your components, they also don't re-render.
So that's the cool thing about it. Let's see if there's anything useful here. So the props are the children and they are absolutely required and they will be, the children will basically be representing all of the routes inside which this layout will use. As I said I think it might be more easier to understand this with an actual code. But this is the one I want to explain next and then we're gonna start some coding.
So the page file. So a page is a UI that is unique to a route. So you can see they have kind of a complex query here. So inside of the app folder they have a blog and then they have a slug and then they have page.vsx. Let's go ahead and let's create this, but let's slowly get to that.
So I'm gonna go ahead and go back inside of my localhost 3000 And let's start a very, very simple. So inside of source, inside of app, I want to create a new route slash blog. How do I do that? I do that by first creating a new folder. So that's how you always start for a new route blog.
And then inside you add a reserved file name which we've just learned page so pages as reserved as layout right if you name this page to this is no longer a route but if you name it page this becomes a route So let's go ahead and do the following. Well, let's go ahead and write blog page. And let's return the blog page. So what's important to learn here is that whenever you're working with page.vsx You have to export default, right? Otherwise it's not going to work.
So let me go ahead and just try this. Let me just try enable developer mode here so you can always see my URL. So now what I'm going to do is I'm going to go to localhost 3000 slash blog. And there we go. I am now on my blog page right here.
So let me just go ahead and show you this. If I forgot to export default blog page and refresh this, there we go. The default export is not a react component. So we need the default export whenever we are working with layout or we are with page.tsx. Great, let's go ahead and let's see what else they are doing.
So after that they add this slug thing so what is the slug thing let's go ahead and check that out so I'm going to go ahead and save the blog page is working perfect and now we could technically for example write one two three and then another page.vsx inside So let me go ahead and write slug page here and div slug page Like this So now if I go to localhost 3000 slash blog slash 123 there we go now it says slug page right because I explicitly wrote 123 here but obviously this is not good right we are most likely not going to hard code our IDs or our slugs for each individual blog post inside of a name like this. So what we can use instead is this. We open pointy brackets like that and then let's go ahead and yeah when you play around with this kind of stuff you might appear you might have this one unsaved file in your open editor and when you click on it it's going to be this weird file in this .next right so it's a very very easy fix you actually don't even have to fix it because next.js will fix it for you but if you want to get rid of it just go ahead and click on this file and just click save and close it and if you're afraid you've messed it up don't worry at all let me just show you one thing about Next.js you can always shut down your app you can go ahead and completely remove the .next folder it doesn't matter and the next time you run your app either by using a BANRUNDEV or NPMRUNDEV it automatically rebuilds so you don't have to worry if you've messed it up there we go so what's important is that now we have blog and then we have this dynamic slug So what does that mean?
Let's go ahead and let's just try and refresh our blog page right here. Nothing has changed but I'm still on slash one two three but the cool thing is if I now try and go to hello-world so for example blog slash hello-world nothing changes. So this is now a dynamic route which can be used to render any part of that URL. And if we want to render what's in the URL we can do that as well as you can see right here they define this params slug string. So let's go ahead and quickly do that.
And I'm going to give you one more example just to make it clearer for you. So this is how I like to write these things. I like to create an interface, slug page props, params, and then slug will be a string. And then inside of here I'm going to go ahead and apply the slug page props inside and I will get my params. And then what I can do here is do params.slug and there we go.
Slug page, hello-world. If I change my URL to 123 now it says 123. If I change it to 321 it says 321. So first of all why did I write slug here? How does it know that slug is going to be inside of here?
Well very simple because we named our variable like that inside of this folder. So if I change this from slug to example id and we got this error by accident right so let's just change this to id but leave the code as it is. As you can see it's no longer working. Well the page still exists right so obviously this three to one is still fine but as you can see it cannot render the slug. That's because we have, we are still looking for this variable called slug, when now we should be looking for ID because that's what we named this folder.
So I'm gonna go ahead and write ID here and there we go. Now it works. And you can go ahead and nest as many routes as you want. So inside of this ID you can go ahead and create settings and inside of it you can add another page.psx and inside of here you have a settings page and a div hello world like this just remember you always have to export default And let's actually call this settings page for slug. So now you can go ahead and go inside of blog, one, two, three, for example, slash settings.
And there we go, settings page for Slack. And what's cool about this nested route is that they also have access to this ID right here. So if I go ahead and write the same interface, let me just copy this interface. You don't have to write the interface, right? By TypeScript for me, this is gonna be the settings page props.
TypeScript for me makes things easier to understand. If that's not true for you, that's completely fine. So params.id again. And there we go. So you can see that we can access these params even in a nested route.
What's important is that they are inside of this folder which has the dynamic ID. So if I happen to move the settings back in directly into the blog for example, you can see that we have a bunch of errors. First of all this 404 right because now there is no slash 123 slash settings we just have slash blog slash settings but now there is no slug right so that's what I kind of wanted to explain And there we have another this unsaved one. And here's another way you can fix it. You can just don't save it, for example.
You don't have to worry about those files because they will be recached and rebuilt again. Great. So I hope that kind of explained the basic way of building routes in Next.js. But there are, of course, some more tricks here. As you can see, we kind of explained this, right?
So you can nest as many nested routes as you want. So you can do category and then item, which would be the equivalent of slash shop slash one slash two and then you would have both category and item in this page.js as I've just demonstrated with the settings page. If you don't know how many routes you're going to have you can also use this catch all route which will simply catch all the variables inside. We are not going to be using this in our project. We actually will for next out but not for our needs.
There are also search params which you can extract, right? They are a prop So this isn't really any convention because we don't do anything inside of our folder naming, right? We just append this to the URL and we can use the search params prop the same way we use the params prop, right? The same way we define that, we can do search params or we can turn it to a client component and then we can use a hook, which is going to change to that. Great, so let's go ahead and see what other conventions do we have in Next.js here.
Let me just scroll a bit down. So I want to cover the layout, I want to cover the page. Loading is pretty self-explanatory and not found so it's used for custom loading pages and custom not found pages. Loading specifically will be visible if we are using suspense and streaming, which is not something we're exactly gonna focus on in this tutorial. So I'm not gonna bother going too deep into this.
Now, of course, we'll briefly explain this later, but it's not the main focus for now. Not founds can be used for custom not founds. Errors are used to catch errors on specific segments. And here's the one that might be interesting for you, is the route. So route is very similar to the page, but it is used to build API routes.
So inside of my app folder I'm gonna go ahead and for example I'm going to create... Actually we can reuse the blog, right? It doesn't matter. Actually let's separate it. So I'm gonna write my test here and inside, instead of page, I'm gonna do route.ts, like that.
And I'm gonna turn this into a very simple get route. So export const get, like this. And I'm going to return next response from next server.json, hello world, like this. There we go. So now let's go to slash test and instead of seeing a page we are now gonna be seeing something else there we go, we get an API response So that's how you build APIs in Next.js.
Quite simple. One little convention that I like to use whenever I build my API routes in Next.js is to use API. I just like to separate my things like this. So I'm again we have this thing popping up you can just close it, save it, don't save it, it doesn't matter. But whenever you have this open remember to close the .next folder.
I saw some people reporting errors that they are coding and nothing is changing. That's because they actually started coding inside of this. We do not code inside of the next folder. We don't care about that. It's just some cache.
Let's go inside of the app folder. So this is how I like to do it. I like to have my API folder and then inside of that I keep all of my routes. I just think it's easier to understand. So now if I refresh here we get a 404 because I have to change my URL to slash API slash test.
There we go. And I believe those are the basic conventions in Next.js and we explained the basic route segment, we explained the nested route segment, we briefly explained the catch-all and the optional catch-all route segment. You're going to see us use this later with NextOut. And these are the ones I want to cover only because I heavily use them and a lot of people don't understand why I use them or what they do. So here is how I like to explain these routes.
We can of course look at the official documentation as well but this is how I like to explain them. So inside of the app folder right here you've learned that every folder we create essentially becomes part of the URL. So let's say... Let me just remove everything from my project here. So I just want an empty page.vsx.
Let's say we want to create a folder inside of the app, which is going to hold all of our authentication routes. So usually, you know, how you would start is we would create an out folder, right? And inside we would add, for example, I don't know, let's go ahead and add something additional right like sign in something or let's just use simpler login and let's add page.psx inside so inside of here I'm gonna go ahead and add a login page div login page like this so what's going on how do we access this route We have to go to slash out and then slash login, right? So I'm gonna go ahead and go to localhost 3000, slash out, slash login. There we go.
That works just fine, right? And now let's go ahead and let's copy and paste this and let's add register. And let's change this to be register page. Also one thing that I forgot to mention the name of the component of the constant you're exporting inside of these pages does not matter. All that matters is that you do a default export.
So this naming register page does not matter. I just like to be consistent and call it like that. You can call this whatever you want. It's going to work just fine. All right, so now we have the login and the register.
So if I go to slash out slash register it works great but it's actually not often seen that we have an out prefix before slash login slash register right so what if I just want to use login and register, but I also want to keep them in their own folder. I don't just want them laying around in my app folder. We can do that using this special types of folders. So if you go ahead and wrap out inside of parentheses here, and you're going to get some errors here. What I do with this weird errors is I just reload my window and then they go away.
So you can do that using command or ctrl shift and p and then just type reload window. So now we have this 404 error right? We can no longer access slash out slash register, nor can we access slash out slash login. But if I go directly to slash login, there we go. I can now access my login page.
Or if I go directly to slash register there we go I can now directly access the register page so that's what we have achieved by using the parentheses around a specific folder it will omit that from the URL so it will not remove it from the router that's important it will just omit this part from the URL that's how we can leverage those specific types of routes now let's take a look at what what Next.js documentation says about this So group routes without affecting the routing, right? I think that's pretty much what we just explained. It's still a part of the router, but it will not be part of the URL. There is an alternative version, which is underscore folder. What this means is that it will opt folder and all child segments out of routing which means not part of the URL and not part of the app router at all.
There are also some parallel and intercepted routes which is not something I'm gonna be working with today. And there are of course some metadata file conventions. If you want to add a favicon you can just put it in your project like this and it will replace the favicon. And there are some OpenGraph things, SEO things, all of those things. But let's go ahead and quickly explain further these two so we can wrap up this chapter.
So one cool thing that this, How exactly is this called? Is there a name for this? I don't think there's a name for this. Let's call them a parentheses folder. So the parentheses folder has a very very neat function besides omitting part of the URL.
What we can also do is we can add layout files inside of it. So let's say that I want every single page inside of my auth to be centered. Well, We can do that the good old way. You know, I can go ahead and add an H full here. Let me just go to my login page, or I think I'm going to maybe need min H screen like that.
Flex items center and justify. Center, There we go. My login page is now centered. One quick tip, if you're wondering how come I have these auto-complete options and how come when I hover I can see stuff like this, That's because of the extension called Tailwind CSS IntelliSense. So I highly recommend you install this.
Great, so now my login page is centered, right? But my register page is not centered. There we go. My register page is not centered. So I could copy and paste this, right?
But what if I plan to have a billion routes inside of here? Well, there is a smarter way of doing it by using the layout file. So let's go inside of out and let's create a new file which is a reserved keyword just like page layout.tsx like this and for now I'm just going to go ahead and quickly go back inside of login and let me just remove this class name like this so I just want to bring it back to normal. We immediately get an error because layouts just like pages need to have a default export. So let's go ahead and let's call this outLayout.
You can of course call this whatever you want, it will not matter. And what's important inside of here is let's first not do anything let's just write out layout and you're going to notice now that even though I'm in localhost 3000 slash register in my case which clearly renders register page what I'm seeing is out layout That is because layout files takes precedence over individual pages. And if you remember the documentation, it is written in there that in outlayout props, children is a required prop. So let's go ahead and extract the children here. Let's go ahead and just quickly assign this and instead of this I'm now going to render children and there we go.
Now I can go on the register and I see the register page and I can go on login and I see the login page. Perfect. So now let's go ahead and try and use the layout to give that styling which we previously had only on login. So I'm going to go ahead and give this a class name of MinHScreen and I'm going to use flanks to center them vertically and horizontally there we go, login page is centered if I go to slash register register page is centered perfect I'm gonna go ahead and remove this now and show you a bit of a more likely example. So more likely layouts will be used for something like this.
We want to share the layout. So it will be something like this, right? Let me go ahead and give this a class name, Plex E2. Actually, okay, let me just go ahead and write something like this. So it will likely have some buttons like home, and this will be, for example, settings, Like that.
And let's go ahead and give this a BG blue 500. Like that. Right? So I'm gonna zoom out. So you would most likely use the out layout to create reusable layouts.
So let's say you wanna have navigation at the top of both your login and register. This is how you would do it without having to write it both in login and both in register. You simply use the layout. So now if I go to slash login, there we go. Login shares this navbar right here.
And what's cool about this navbar is that it will only render once. So it will not re-render for the change from register to login. That's the cool thing about it. It's also the optimized way of doing things. Great!
So I think we've kind of learned the basics of routing. Let's just go ahead and do one more thing to explain that underscore folder. So one convention, one thing about Next.js in general is that you can create components anywhere you want. So if I want to go ahead and create a test component here I can do that. So I can just do export const, this is a test component, and I will return a paragraph test component.
I can do that anywhere. So in my login, I can just very simply import that. And I can render a test component. So let me go to my login here. Oops, import test from test.
I completely forgot how to do this. And it needs to be destructed. There we go. Now it renders a test component. And I can also go ahead and change this to use a default expert.
If I want to. So some people prefer default, some people prefer named export. So if I do the default, then it will be import test from test. And it's still working just fine. That's not the issue.
The problem is, what if I want to have a component called page.tsx? How would I do that? Well, let's try it out. Let's remove the test.tsx component. And let me close everything here.
Let's go inside of login and let's create a new folder. And we're going to call this components, like this. And inside, I'm going to create a page.dsx and I'm going to export default page component div whoops page component Do you already know what's going to happen now? So let me just remove this import, we don't need this anymore. I will just write login page here.
So do you know what will happen if I go to slash login slash components now? If I go to slash login slash components, There we go. It renders page component. That's definitely not what we intended to do. I wanted this components folder to be used as something I can import.
So I wanted to import a page component from components page right this is what I wanted to do I wanted to use it on the login page I did not intend for this to be a route on its own so that's where this comes in handy adding an underscore so this now not only removes it from the URL but it also removes it from the app router in general so if I go ahead and try to go to slash login slash components now there we go exactly what I expected 404 if I go and try underscore components same thing it no longer exists so that is that last thing that I wanted to explain which is where is it there we go opt-out folder and all child segments out of routing right here. Great, great, great job. So what I want to do now is I just want to show you, I will, I don't know if you, you don't have to of course follow this instructional part along, right? So what I will do is I will remove the out folder. We don't need it.
I just want us to have the basic page.vsx inside. Let me go back here and I will refresh my localhost at the root. There we go. Great, great job!