Β 

Getting Started with Next.js App Router Capabilities

image
Β·

August 11, 2024

Getting Started with Next.js App Router Capabilities

Welcome back to our series on building a SaaS application using Next.js, Prisma, and Supabase! In this post, we'll delve into the new Next.js app router capabilities. We'll explore how to set up the app structure, configure routes, and manage navigation effectively. By the end of this post, you'll have a solid understanding of how to leverage Next.js routing features to build a scalable and maintainable application.

What is the Next.js App Router?

The Next.js app router simplifies the process of defining and managing routes in your application. It uses a file-based routing system, which means that the file and directory structure of your project directly determines the routes of your application. This approach makes it easy to organize and navigate your app's pages and components.

Setting Up the App Structure

Let's start by organizing our project directory to take full advantage of Next.js's app router. Here's a basic structure for our SaaS application:

my-saas-app/
β”œβ”€β”€ pages/
β”‚   β”œβ”€β”€ api/
β”‚   β”œβ”€β”€ index.tsx
β”‚   β”œβ”€β”€ dashboard.tsx
β”‚   └── auth/
β”‚       β”œβ”€β”€ login.tsx
β”‚       └── register.tsx
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ Layout.tsx
β”‚   β”œβ”€β”€ Navbar.tsx
β”‚   └── Footer.tsx
β”œβ”€β”€ styles/
β”‚   └── globals.css
└── supabaseClient.ts

Configuring Routes and Navigation

Creating Pages

In Next.js, each file inside the pages directory becomes a route in your application. Let's create some basic pages for our SaaS app.

  1. Home Page (pages/index.tsx)
1// pages/index.tsx 2import { NextPage } from 'next' 3import Head from 'next/head' 4import Link from 'next/link' 5 6const Home: NextPage = () => { 7 return ( 8 <div className="min-h-screen flex flex-col items-center justify-center bg-gray-100"> 9 <Head> 10 <title>Home | My SaaS App</title> 11 </Head> 12 <main className="flex flex-col items-center justify-center w-full flex-1 px-20 text-center"> 13 <h1 className="text-6xl font-bold"> 14 Welcome to <a className="text-blue-600" href="/">My SaaS App</a> 15 </h1> 16 <p className="mt-3 text-2xl"> 17 Get started by navigating to{' '} 18 <Link href="/dashboard"> 19 <a className="text-blue-600">Dashboard</a> 20 </Link> 21 </p> 22 </main> 23 </div> 24 ) 25} 26 27export default Home 28
  1. Dashboard Page (pages/dashboard.tsx)
1// pages/dashboard.tsx 2import { NextPage } from 'next' 3import Head from 'next/head' 4import Link from 'next/link' 5 6const Dashboard: NextPage = () => { 7 return ( 8 <div className="min-h-screen flex flex-col items-center justify-center bg-gray-100"> 9 <Head> 10 <title>Dashboard | My SaaS App</title> 11 </Head> 12 <main className="flex flex-col items-center justify-center w-full flex-1 px-20 text-center"> 13 <h1 className="text-6xl font-bold">Dashboard</h1> 14 <p className="mt-3 text-2xl"> 15 Welcome to your dashboard. Go back to{' '} 16 <Link href="/"> 17 <a className="text-blue-600">Home</a> 18 </Link> 19 </p> 20 </main> 21 </div> 22 ) 23} 24 25export default Dashboard 26
  1. Login Page (pages/auth/login.tsx)
1// pages/auth/login.tsx 2import { NextPage } from 'next' 3import Head from 'next/head' 4import Link from 'next/link' 5 6const Login: NextPage = () => { 7 return ( 8 <div className="min-h-screen flex flex-col items-center justify-center bg-gray-100"> 9 <Head> 10 <title>Login | My SaaS App</title> 11 </Head> 12 <main className="flex flex-col items-center justify-center w-full flex-1 px-20 text-center"> 13 <h1 className="text-6xl font-bold">Login</h1> 14 <form className="mt-8 space-y-6"> 15 <div className="rounded-md shadow-sm -space-y-px"> 16 <div> 17 <label htmlFor="email" className="sr-only">Email address</label> 18 <input id="email" name="email" type="email" autoComplete="email" required className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-t-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm" placeholder="Email address" /> 19 </div> 20 <div> 21 <label htmlFor="password" className="sr-only">Password</label> 22 <input id="password" name="password" type="password" autoComplete="current-password" required className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm" placeholder="Password" /> 23 </div> 24 </div> 25 <div> 26 <button type="submit" className="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"> 27 Sign in 28 </button> 29 </div> 30 </form> 31 <p className="mt-2 text-sm text-gray-600"> 32 Or{' '} 33 <Link href="/auth/register"> 34 <a className="font-medium text-indigo-600 hover:text-indigo-500">create a new account</a> 35 </Link> 36 </p> 37 </main> 38 </div> 39 ) 40} 41 42export default Login 43
  1. Register Page (pages/auth/register.tsx)
1// pages/auth/register.tsx 2import { NextPage } from 'next' 3import Head from 'next/head' 4import Link from 'next/link' 5 6const Register: NextPage = () => { 7 return ( 8 <div className="min-h-screen flex flex-col items-center justify-center bg-gray-100"> 9 <Head> 10 <title>Register | My SaaS App</title> 11 </Head> 12 <main className="flex flex-col items-center justify-center w-full flex-1 px-20 text-center"> 13 <h1 className="text-6xl font-bold">Register</h1> 14 <form className="mt-8 space-y-6"> 15 <div className="rounded-md shadow-sm -space-y-px"> 16 <div> 17 <label htmlFor="email" className="sr-only">Email address</label> 18 <input id="email" name="email" type="email" autoComplete="email" required className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-t-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm" placeholder="Email address" /> 19 </div> 20 <div> 21 <label htmlFor="password" className="sr-only">Password</label> 22 <input id="password" name="password" type="password" autoComplete="new-password" required className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm" placeholder="Password" /> 23 </div> 24 </div> 25 <div> 26 <button type="submit" className="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"> 27 Sign up 28 </button> 29 </div> 30 </form> 31 <p className="mt-2 text-sm text-gray-600"> 32 Already have an account?{' '} 33 <Link href="/auth/login"> 34 <a className="font-medium text-indigo-600 hover:text-indigo-500">Sign in</a> 35 </Link> 36 </p> 37 </main> 38 </div> 39 ) 40} 41 42export default Register 43

Creating Layout and Navigation Components

Next, let's create a layout component that will wrap our pages and include a common navigation bar.

  1. Layout Component (components/Layout.tsx)
1// components/Layout.tsx 2import { ReactNode } from 'react' 3import Navbar from './Navbar' 4import Footer from './Footer' 5 6interface LayoutProps { 7 children: ReactNode 8} 9 10const Layout: React.FC<LayoutProps> = ({ children }) => { 11 return ( 12 <div className="flex flex-col min-h-screen"> 13 <Navbar /> 14 <main className="flex-grow">{children}</main> 15 <Footer /> 16 </div> 17 ) 18} 19 20export default Layout 21

Let's Build Something Amazing Together

Ready to transform your digital landscape? Contact Codeks today to book a free consultation. Let's embark on a journey to innovation, excellence, and success together.