With ever so increasing rise in popularity of Next.js, it has become quite a standard to use it for a server-side React web applications. So that means Next.js cheat sheet will be your main asset going forward.

It gets all the features of React.js – the JavaScript’s UI library to build components and adds so many additional features that sometimes as a Next.js developer it’s hard to catch up on the different code snippets, commands to run, packages to install and more.

To solve this issue, we have created a to-the-point cheatsheet of all the Next.js features that will benefit to all developer – be it a beginner or a pro. Let’s dive in!

What is Next.js?

According to its definition on the official docs:

  • Next.js is a flexible React framework that gives you building blocks to create fast web applications.
next.js Cheat sheet

Basically, it provides some of the crucial features and building blocks on top of a standard React.js application to make a modern website and apps.

Here are some of those important features (amongst others) which we will discuss on:

  1. Setup
  2. Create pages
  3. Fetch data
  4. Style your Next.js app
  5. Optimize images and fonts
  6. Linting your code
  7. TypeScript support
  8. Using scripts
  9. App-level routing
  10. API routing
  11. Middlewares
  12. Authentication
  13. Testing 

Next.js Cheat sheet 2022

Given below are the the next.js cheat sheet that you can use in your next project.

1. Setup

To create a Next.ja app, the recommended process is to use the official create-next-app command which sets up all the necessary files, folders and configuration automatically.

npx create-next-app@latest

# OR

yarn create next-app

Then run npm run dev or yarn dev to start the local development server on http://localhost:3000.

Alternatively, if you manually want to install Next.js, then first you should install next, react and react-dom in your project as:

npm install next react react-dom

# OR

yarn add next react react-dom

Inside your package.json file, add the following scripts:

"scripts": {

  "dev": "next dev",

  "build": "next build",

  "start": "next start",

  "lint": "next lint"

}

2. Create pages

To create a simple static page, under the pages directory, create a file named demo.js which exports a React component:

function Demo() {

  return <h1>Demo</h1>

}

export default Demo

This page will be available at http://localhost:3000/demo of your local environment.

3. Fetch data

There are many ways to fetch data from external sources to your Next.js app, here are some:

  • getServerSideProps: if you want your app to pre-render a page on each request, then getServerSideProps function should be exported as so:

export async function getServerSideProps(context) {

  return {

    props: {},

  }

}

Here’s an example to fetch data at request time which pre-renders the result it gets back from the data source:

function Page({ data }) {

  // Code to render the `data`

}

export async function getServerSideProps() {

  const res = await fetch(`https://.../data`)

  const data = await res.json()

  return { props: { data } }

}

export default Page

  • getStaticPaths: if you want to dynamically generate routes on your app alongside with getStaticProps then, getStaticPaths will pre-render all the paths provided to it as:

export async function getStaticPaths() {

  return {

    paths: [

      { params: { ... } }

    ],

    fallback: true 

  };

}

  • getStaticProps: if you want Next.js to generate a page at build time using the props passed to it, then getStaticProps should be exported as:

export async function getStaticProps(context) {

  return {

    props: {}, 

  }

}

Note that the props here must be passed to the page component as props. An example of its usage when you want the data to fetch from a CMS is as follows:

function BlogPosts ({ posts }) {

  return (

    <>

      {posts.map((post) => (

        <h1>{post.title}</h1>

        <p>{post.summary}</p>

      ))}

    </>

  )

}

export async function getStaticProps() {

  const res = await fetch('https://.../posts')

  const posts = await res.json()

  return {

    props: {

      posts,

    },

  }

}

export default BlogPosts

  • Incremental Static Regeneration(ISR): if you want to create or update existing static pages after you’ve build your site, then ISR allows you do statically generate on per-page basis. This means that now you don’t need to re-build the entire site from scratch.
  •  
  • For this to work, you just need to add the revalidate prop to getStaticProps method:

export async function getStaticProps(context) {

  return {

    props: {},

    revalidate: 5 // this means the request to re-generate the page will berevalidated once in every 5 seconds

  }

}

  • Fetch data on client-side: this can be done in two different ways — either via the useEffect hook as:

function User() {

  const [data, setData] = useState(null)

  const [isLoading, setLoading] = useState(false)

  useEffect(() => {

    setLoading(true)

    fetch('api/user-data')

      .then((res) => res.json())

      .then((data) => {

        setData(data)

        setLoading(false)

      })

  }, [])

  if (isLoading) return <p>Loading user data...</p>

  if (!data) return <p>No user data found</p>

  return (

    <div>

      <h1>{data.name}</h1>

      <p>{data.bio}</p>

    </div>

  )

}

or via the SWR library which handles caching, revalidation, focus tracking, refetching on intervals, and more as:

import useSWR from 'swr'

const fetcher = (...args) => fetch(...args).then((res) => res.json())

function User() {

  const { data, error } = useSWR('/api/user-data', fetcher)

  if (error) return <div>Failed to load user data</div>

  if (!data) return <div>Loading user data...</div>

  return (

    <div>

      <h1>{data.name}</h1>

      <p>{data.bio}</p>

    </div>

  )

}

4. Style your Next.js app

There are many ways to style your apps, some of the common methods are:

  • Global styling: import the global styles.css in your pages/_app.js where these styles will apply to all pages and components in your app as:

import '../styles.css'

export default function MyApp({ Component, pageProps }) {

  return <Component {...pageProps} />

}

  • Component-Level CSS: Next.js supports CSS Modules where you can name the files as [name].module.css and then import it on a specific component. Here’s an example:

// Button.module.css 

.error {

  color: white;

  background-color: red;

}

// Button.jsx

import styles from './Button.module.css'

export function Button() {

  return (

    <button

      type="button"

      className={styles.error}

    >

      Cancel

    </button>

  )

}

  • Using SASS: first you need to install the SASS package on your Next.js app:

npm install --save-dev sass

Then you can configure the SASS compiler options in next.config.js file:

const path = require('path')

module.exports = {

  sassOptions: {

    includePaths: [path.join(__dirname, 'styles')],

  },

}

Also ReadAngular vs React vs Vue

5. Optimize images and fonts

To optimize images you should use the built-in Image component. Install it in your project as:

import Image from 'next/image'

Then give it a src attribute as shown in the following example:

import Image from 'next/image'

const myLoader = ({ src, width, quality }) => {

  return `https://example.com/${src}?w=${width}&q=${quality || 75}`

}

const MyImage = (props) => {

  return (

    <Image

      loader={myLoader}

      src="me.png"

      alt="Picture of the author"

      width={500}

      height={500}

    />

  )

}

Next.js automatically optimizes the fonts used by automatically inline font CSS at build time. But to use a web font, you can add it to the Custom Document file as:

// pages/_document.js

import Document, { Html, Head, Main, NextScript } from 'next/document'

class MyDocument extends Document {

  render() {

    return (

      <Html>

        <Head>

          <link

            href="https://fonts.googleapis.com/css2?family=Inter&display=optional"

            rel="stylesheet"

          />

        </Head>

        <body>

          <Main />

          <NextScript />

        </body>

      </Html>

    )

  }

}

export default MyDocument

6. Linting your code

You can use ESLint out-of-the-box for linting. Simply add the following script to the package.json file:

"scripts": {

  "lint": "next lint"

}

Now you can run npm run lint or yarn lint to start the linter. If you are using ESLint in a monorepo where Next.js isn’t installed in your root directory, the you just simply add the rootDir to your .eslintrc file:

{

  "extends": "next",

  "settings": {

    "next": {

      "rootDir": "packages/my-app/"

    }

  }

}

To use Prettier with ESLint settings, first install the dependency:

npm install --save-dev eslint-config-prettier

# OR

yarn add --dev eslint-config-prettier

And then add prettier to your existing ESLint configuration file:

{

  "extends": ["next", "prettier"]

}

7. TypeScript support

To use TypeScript with Next.js when you start an app, use the create-next-app command along with the –ts or –typescript flag:

npx create-next-app@latest --ts

# or

yarn create next-app --typescript

This will spin up a new Next.js project with all the Typescript files and components without any extra configuration. 

But if you want to integrate TypeScript in an existing project then, create a new tsconfig.json file at the root of the project directory. Then run npm run dev or yarn dev, with this Next.js wil guide you through the installation of the required packages to finish setting up TypeScript integration.

8. Using scripts

The native HTML <script> element is replaced by next/script component in Next.js. Here’s an example of loading a Google Analytics script:

import Script from 'next/script'

export default function Home() {

  return (

    <>

      <Script src="https://www.google-analytics.com/analytics.js" />

    </>

  )

}

First, you import the script component:

import Script from 'next/script'

Next, there are different ways to handle scripts with this component which can be set by the strategy property with one of the following three values:

  1. beforeInteractive: load the script before the page is interactive.
  2. afterInteractive: load the script immediately after the page becomes interactive.
  3. lazyOnload: load the script during idle time.

Here’s an example:

<Script

  src="https://cdn.jsdelivr.net/npm/cookieconsent@3/build/cookieconsent.min.js"

  strategy="beforeInteractive"

/>

9. App-level routing

Next.js has file-system based router which works on the concept of pages. You can either have index routes like pages/index.js which map to / and pages/blog/index.js which map to /blog.

Or you can have nested routes where it supports nested files. For example, a file located on pages/blog/my-post.js will route to /blog/my-post.

For dynamic routes, you need to use the bracket syntax so that it can match named parameters. For example, pages/[username]/settings.js will map to /johndoe/settings.

The <Link> component is used to do client-side route transitions. First, you need to import it as:

import Link from 'next/link'

Then, use it in a component:

import Link from 'next/link'

function Home() {

  return (

    <ul>

      <li>

        <Link href="/">

          <a>Home</a>

        </Link>

      </li>

      <li>

        <Link href="/about">

          <a>About Us</a>

        </Link>

      </li>

      <li>

        <Link href="/blog/hello-world">

          <a>Blog Post</a>

        </Link>

      </li>

    </ul>

  )

}

export default Home

For dynamic paths, you can use string interpolation to create the desired path:

import Link from 'next/link'

function Posts({ posts }) {

  return (

    <ul>

      {posts.map((post) => (

        <li key={post.id}>

          <Link href={`/blog/${encodeURIComponent(post.slug)}`}>

            <a>{post.title}</a>

          </Link>

        </li>

      ))}

    </ul>

  )

}

export default Posts

10. API routing

Any file inside the pages/api folder is mapped to /api/* which will be treated as an API endpoint. For example, to return a JSON response with a OK status code of 200, you can export a handler function with req and res passed as parameters:

export default function handler(req, res) {

  res.status(200).json({ name: 'John Doe' })

}

To handle different HTTP methods, you can use the req.method in your request handler:

export default function handler(req, res) {

  if (req.method === 'POST') {

    // Process a POST request

  } else {

    // Handle any other HTTP method

  }

}

11. Middlewares

  1. To use middlewares in Next.js, first install the latest version of Next:

npm install next@latest

  1. Then create a _middleware.ts file inside your /pages directory
  2. Finally, export a middleware function form the same file:

import type { NextFetchEvent, NextRequest } from 'next/server'

export function middleware(req: NextRequest, ev: NextFetchEvent) {

  return new Response('Hello, world!')

}

For example, here is an example where a middleware is used for logging:

import { NextRequest } from 'next/server'

// Regex for public files

const PUBLIC_FILE = /\.(.*)$/

export default function middleware(req: NextRequest) {

  // Only log for visited pages

  if (!PUBLIC_FILE.test(req.nextUrl.pathname)) {

    // We fire and forget this request to avoid blocking the request until completion

    // and let logging occur in the background

    fetch('https://in.logtail.com', {

      method: 'POST',

      headers: {

        'Content-Type': 'application/json',

        Authorization: `Bearer ${process.env.LOGTAIL_TOKEN}`,

      },

      body: JSON.stringify({

        message: 'Log from the edge',

        nested: {

          page: req.nextUrl.href,

          referrer: req.referrer,

          ua: req.ua?.ua,

          geo: req.geo,

        },

      }),

    })

  }

}

Also Read: React Table: A detailed guide with Examples

12. Authentication

There are many different ways to authenticate a user in a Next.js app. Some of the common ones are:

  1. Authenticating statically generated pages: here, your page can render a loading state from the server after which it will fetch the user data from client-side. In the following example, the page render a loading skeleton state and once the request is met, it shows user’s name:

import useUser from '../lib/useUser'

import Layout from '../components/Layout'

const Profile = () => {

  // Fetch the user client-side

  const { user } = useUser({ redirectTo: '/login' })

  // Server-render loading state

  if (!user || user.isLoggedIn === false) {

    return <Layout>Loading...</Layout>

  }

  // Once the user request finishes, show the user

  return (

    <Layout>

      <h1>Your Profile</h1>

      <pre>{JSON.stringify(user, null, 2)}</pre>

    </Layout>

  )

}

export default Profile 

  1. Authenticating server-rendered pages: here you need to export a async getServerSideProps() function from a page by which Next.js will pre-render this page on each request. Here’s an example where if there is a session, then the user is returned as a prop to the Profile component:

import withSession from '../lib/session'

import Layout from '../components/Layout'

export const getServerSideProps = withSession(async function ({ req, res }) {

  const { user } = req.session

  if (!user) {

    return {

      redirect: {

        destination: '/login',

        permanent: false,

      },

    }

  }

  return {

    props: { user },

  }

})

const Profile = ({ user }) => {

  // Show the user. No loading state is required

  return (

    <Layout>

      <h1>Your Profile</h1>

      <pre>{JSON.stringify(user, null, 2)}</pre>

    </Layout>

  )

}

export default Profile

  1. Authenticating with third-party providers: for common authentication providers like Auth0, Firebase, Supabase etc, you can take a look at the official GitHub repository for examples on how to setup and configure for your own Next.js app.

13. Testing

Just like with authentication, testing can be done in a lot of different ways and with different testing tools. Here’s how to setup testing with common tools:

  1. Testing with Cypress: start off with the with-cypress example to quickly start a Next.js app with Cypress as:

npx create-next-app@latest --example with-cypress with-cypress-app

Or manually, install the cypress package:

npm install --save-dev cypress

Then add it to the scripts field of your package.json file:

"scripts": {

  ...

  "cypress": "cypress open",

}

Finally, run Cypress with the following command:

npm run cypress

To create a Cypress test file. Simple create a file under cypress/integration/app.spec.js as:

describe('Navigation', () => {

  it('should navigate to the about page', () => {

    // Start from the index page

    cy.visit('http://localhost:3000/')

    // Find a link with an href attribute containing "about" and click it

    cy.get('a[href*="about"]').click()

    // The new url should include "/about"

    cy.url().should('include', '/about')

    // The new page should contain an h1 with "About page"

    cy.get('h1').contains('About Page')

  })

})

  1. Testing with Jest and React Testing Library: again you can use it quickly with the community provided with-jest example while you spin off a new Next project:

npx create-next-app@latest --example with-jest with-jest-app

Or manually, you can install Jest, React Testing Library and Jest DOM packages:

npm install --save-dev jest @testing-library/react @testing-library/jest-dom

Then create a jest.config.js file in the project’s root directory:

const nextJest = require('next/jest')

const createJestConfig = nextJest({

  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment

  dir: './',

})

// Add any custom config to be passed to Jest

const customJestConfig = {

  // Add more setup options before each test is run

  // setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],

  // if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work

  moduleDirectories: ['node_modules', '<rootDir>/'],

  testEnvironment: 'jest-environment-jsdom',

}

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async

module.exports = createJestConfig(customJestConfig)

Add a test script to the package.json file:

"scripts": {

  ...

  "test": "jest --watch"

}

Then create a Jest test file under __tests__/index.test.jsx as:

import { render, screen } from '@testing-library/react'

import Home from '../pages/index'

describe('Home', () => {

  it('renders a heading', () => {

    render(<Home />)

    const heading = screen.getByRole('heading', {

      name: /welcome to next\.js!/i,

    })

    expect(heading).toBeInTheDocument()

  })

})

To run the test simply execute the npm run test command.

In this article, you got to know what is Next.js in brief, Next.js Cheat sheet and how it helps in making a modern React-based websites and apps. Then you saw how to setup a Next.js project, how to fetch data, optimise assets, add TypeScript support, use linters, integrate testing tools and more!