Next.js has one of the most robust and easy to use routes that you can just use out of the box. You don’t need to hassle by configuring it.
Because Next.js follows the Convention over Configuration
philosophy, every file inside the pages
directory will be automatically considered as a route.
So, let’s see what different types of routing we get with Next.
Static Routing
Let’s create an About
page for our blog app
For it, just create a file about.js
insided pages
directory
1 2 | touch pages/about.js |
with content
1 2 3 4 5 6 | <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">About</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span><span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span>About<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
That’s it. Next’s built HMR should automatically pick up the added file, and create a route for it.
Just go to localhost:3000/about
and you should see your about page.
Now, let’s think for some reason you need to structure your about
routes in a different
maybe
1 2 3 4 | localhost:3000/about -> Opens the about us localhost:3000/about/contact -> Opens the contact page localhost:3000/about/some_random_page -> Opens some random page you need to show |
For that, you need your folder structured like this
1 2 3 4 5 6 | > pages > about index.js contact.js some_random_page.js |
Let’s create them
1 2 3 4 | mkdir about mv pages/about.js pages/about/index.js |
We renamed our old about.js
file to index.js
and moved it inside the pages/about
folder.
If you refresh the page, it’ll behave in the same way.
1 2 | touch pages/about/contact.js |
1 2 3 4 5 6 | <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Contact</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span><span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span>Contact Us<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
and your weird random page
1 2 | touch pages/about/some_random_page.js |
1 2 3 4 5 6 | <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">SomeRandomPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span><span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span>bla bla bla<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Dynamic Routing
Ofcourse, you can just use Static routes
for some simple urls.
Let’s think you’re creating a blog and you need to show your posts through posts/1
url
The folder structure for that will be
1 2 3 4 5 | > pages > posts index.js [id].js |
the index.js
file is for your all posts
page.
What about the weird [id].js
file?
This is a special syntax used by Next.js called slugs. The string inside the [
and ]
brackets denote which parameters the page will receive.
Let’s see the code
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">import</span> <span class="token punctuation">{</span> useRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'next/router'</span> <span class="token keyword">const</span> <span class="token function-variable function">Post</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token function">useRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> id <span class="token punctuation">}</span> <span class="token operator">=</span> router<span class="token punctuation">.</span>query <span class="token keyword">return</span> <span class="token operator"><</span>p<span class="token operator">></span>Post<span class="token operator">:</span> <span class="token punctuation">{</span>id<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Post |
We need to import the useRouter
module from next/router
to catch which param was sent in the URL.
That is done by the following code
1 2 3 | <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token function">useRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> id <span class="token punctuation">}</span> <span class="token operator">=</span> router<span class="token punctuation">.</span>query <span class="token comment">// < { id } because we named the slug in filename as [id].js</span> |
if you instead named your slug as [post_id].js
, then the code should be
1 2 3 | <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token function">useRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> post_id <span class="token punctuation">}</span> <span class="token operator">=</span> router<span class="token punctuation">.</span>query |
Now, if you visit the url posts/1234567
the page will receive the data { "id": "1234567" }
and render
Catch all routes
So, what about when you want to pass more data through the url and catch them in the following page.
in that case, we will need Catch all routes
. It’s syntax is like
1 2 3 4 5 | <span class="token operator">></span> pages <span class="token operator">></span> posts index<span class="token punctuation">.</span>js <span class="token punctuation">[</span><span class="token operator">...</span>slug<span class="token punctuation">.</span>js<span class="token punctuation">]</span> |
This will match posts/1
, at the same time match posts/1/2/3/abc
and so on.
Remember with [id].js
we received the vlaue like { "id": "1234567" }
With […slug.js] we will receive the value in an array.
So, posts/a/b
will give you { "slug": ["a", "b"] }
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">import</span> <span class="token punctuation">{</span> useRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'next/router'</span> <span class="token keyword">const</span> <span class="token function-variable function">Article</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token function">useRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span> slug <span class="token operator">=</span> router<span class="token punctuation">.</span>query console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>slug<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token operator"><</span>p<span class="token operator">></span>Article<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Article |
If you go to localhost:3000/articles/12/32
it’ll get an array [12, 32]
That’s it.
Shallow Routing
Shallow routing is used for changing the url without fetching any data.
This means getStaticProps
or getServerSideProps
will not be called.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import { useEffect } from 'react' import { useRouter } from 'next/router' // Current URL is '/' function Page() { const router = useRouter() useEffect(() => { // Always do navigations after the first render router.push('/?counter=123', undefined, { shallow: true }) }, []) useEffect(() => { // The counter changed! }, [router.query.counter]) } export default Page |
The URL will get updated to /?counter=123
and the page won’t get replaced, only the state of the route is changed.