Next.js 13 tutorial with new features

Next.js 13 tutorial with new features

In this tutorial we'll learn about the new features of Next.js 13 by building a demo web application from scratch.

Creating a Next.js 13 app

Let's get started by installing Next.js 13. Head over to a new terminal and run the following command:

npx create-next-app@latest 

You'll be prompted as follows:

✔ What is your project named? … next13demo
✔ Would you like to use TypeScript with this project? … No / Yes
✔ Would you like to use ESLint with this project? … No / Yes

I named the app next13demo and answered No for the other questions!

Next.js 13 app directory

Since this is a tutorial about the new features of Next.js 13, we'll use the app/ directory which aims to improve routing and layouts in Next.js.

This is still an experimental feature so we need to enable it. Open the next.config.js file and update it as follows:

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  experimental: { appDir: true }
}

module.exports = nextConfig

Next, create the app/ directory with a page.jsx file and the following contents:

export default function Page() {
  return <p>Hello, Next.js 13</p>;
}

Before you proceed, you need to remove the pages/index.js or Next.js 13 will throw the following error: error - Conflicting app and page file was found, please remove the conflicting files to continue.

After that start the dev server using the following command from the root of your Next.js 13 project:

npm run dev

You'll get the following output

ready - started server on 0.0.0.0:3000, url: http://localhost:3000
warn  - You have enabled experimental feature (appDir) in next.config.js.
warn  - Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk.
info  - Thank you for testing `appDir` please leave your feedback at https://nextjs.link/app-feedback

event - compiled client and server successfully in 546 ms (208 modules)
wait  - compiling /page (client and server)...

Your page app/page.jsx did not have a root layout, we created app/layout.js for you.

You'll be able to visit your Next.js 13 web app from http://localhost:3000/.

Next.js 13 layouts

You can see that Next created an app/layout.js for us with the following contents:

export default function RootLayout({ children }) {
  return (
    <html>
      <head></head>
      <body>{children}</body>
    </html>
  )
}

The layout function accepts a layout or a page as a child. Accodring to the official website:

A layout is UI that is shared between multiple pages. On navigation, layouts preserve state, remain interactive, and do not re-render.

Layouts are a great feature that enables developers to share common logic between pages.

For example, we can put the top navigation menu in the app/layout.js file. Create a app/navbar.jsx file and add the following contents:

import Link from "next/link";

export default () => {
  return (
      <ul>
        <li>
          <Link href="/">Home</Link>
        </li>
        <li>
          <Link href="/user/login">Login</Link>
        </li>
        <li>
          <Link href="/user/signup">Sign Up</Link>
        </li>
      </ul>
  );
};

Next, update the app/layout.js file as follows:

import Navbar from "./navbar";

export default function RootLayout({ children }) {
  return (
    <html>
      <head></head>
      <body>
       <Navbar />
       {children}
      </body>
    </html>
  )
}

You can then create the other two pages inside tha app/ folder in the same way. Create app/user/login/page.jsx with the following contents:

export default function Page() {
  return <p>Login</p>;
}

Then create the app/user/signup/page.jsx with the following contents:

export default function Page() {
  return <p>Signup</p>;
}

React Server Components vs. Client Components

In Next.js 13 all components inside the app directory are React Server Components by default. You can use the use client directive at the top of the component designed for the client.

Let's make the navigation component a client component. Open the app/navbar.jsx file and update it as follows:

"use client";
import Link from "next/link";

export default () => {
  return (
      <ul>
        <li>
          <Link href="/">Home</Link>
        </li>
        <li>
          <Link href="/user/login">Login</Link>
        </li>
        <li>
          <Link href="/user/signup">Sign Up</Link>
        </li>
      </ul>
  );
};

You specifically must add use client when:

  • Making use of useState or useEffect hooks from React
  • Making use of some browser APIs
  • You need to add certain event listeners

In other circumstances, where you don't need something from the client, it's ideal to leave components alone and let Next.js render them as Server Components. This will assist to guarantee that there is as little client-side JavaScript code as possible.

Next.js 13 nested layouts

We can also use nested layouts. Inside the user/ sub route we can add a layout.jsx with the following contents:

export default function UserLayout({ children }) {
  return (
    <main>
     <h2>Auth</h2>
     {children}
    </main>
  )
}

If your visit your Next.js 13 app, you can see that we've a shared UI between the three pages and thanks to the sub-route layout, we also have a shared UI that contains the Auth header between the two pages of the user/ route.