There’s plenty to consider when building a React application from scratch. You must bundle your app using a module bundler. You must split your code to optimize performance. You may also need to use server-side rendering and static pre-rendering for better SEO.
Next.js is a React framework that can solve all these problems, and more. It requires zero configuration, automatically compiles and bundles code, and renders your app production-ready from the very start. A simple npm run dev
gets a server up and running on your localhost.
In this post, we will explore Next.js in more detail. We’ll talk about its architecture, types of applications you can build with it, share some code snippets, and explain why it’s the framework-of-choice for web development.
Next.js is an open-source, flexible framework that simplifies the building of fast, user-friendly, and SEO websites. It provides developers with all the building blocks they need to create a fully functioning, highly dynamic, and fast-loading website.
Whether you want to implement a hybrid data fetching and rendering approach, add API routes to your application, connect to a database, or integrate with a third-party application, Next.js enables you to do it all using a few lines of code.
Here are some other cool features that Next.js provides out of the box:
You can virtually build any kind of website or digital product using Next.js. Here are a few examples:
npx create-next-app@latest
to create a new application.npm run dev
to start the app server on localhost:3000
.You will be able to view your website by opening http://localhost:3000 on the browser. Edit the pages/index.js file and see your website change on the browser.
ISR allows you to use static generation on a per-page basis, meaning you don’t have to regenerate the entire website. You get to enjoy the advantages of static while scaling to millions of pages.
Next.js enables developers to use multiple data fetching techniques in the same project. It allows them to render some or all of the content on the server side before sending it to the browser. It does several things under the hood to optimize code in development and production environments.
In a development setup, it optimizes for developers by providing features like ESLint integration and Fast Refresh. It uses a Rust-based compiler which is 17 times faster than Babel, another famous compiler for JavaScript.
Its Speedy Web Compiler (SWC) component can automatically compile, minify, and bundle code.
Built-in support for code splitting ensures that only the required code is loaded for an entry point, which significantly improves the speed of a website.
When in production, Next.js optimizes for the end users. As you build your application, it transforms your code into production-ready files that are fine-tuned for maximum performance. It also supports three forms of rendering: server-side rendering, static site generation, and client-side rendering.
Developers have the luxury to choose different forms of rendering for different pages, depending on the use case. By using a hybrid rendering approach, they can deliver truly dynamic and intuitive user experiences.
Next.js is the go-to framework for website development because it’s great for user experience, allows developers to build versatile React apps, and has a rich developer community. Here are some other reasons why you should choose Next.js for your next web app:
Next.js offers TypeScript support out of the box. There is no need to perform any manual configurations. This makes it easy for developers to write TypeScript code inside a React application. Creating a TypeScript project is as easy as running the following command:
npx create-next-app@latest --ts
If you have an existing project, you can enable TypeScript support by following these steps:
tsconfig.json
in the root directory. Next.js will automatically fill this file with the default values.npm run dev
. Next.js should prompt you to execute the required command to install TypeScript. For example, you may get:# Please install TypeScript, @types/react, and @types/node by running:
#
# yarn add --dev typescript @types/react @types/node
That’s it! You are now ready to convert your .js files to .tsx and write strongly-typed TypeScript code!
User experience plays a crucial role in the success of an online business. A website with bad usability leads to high bounce rates and abandoned carts. Fortunately, you can use Next.js to build expansive, customized user experiences.
Unlike other frameworks which limit a developer’s ability to tweak code, Next.js gives developers full control over customization. It’s packed with different dynamic routing and scripting features which allow developers to tweak any and all parts of their applications.
Using the Link component, you can implement client-side navigation. E.g., the following code can be used to navigate back to the homepage.
import Link from 'next/link';
export default function MyFunc() {
return (
<>
<h1>Hello</h1>
<h2>
<Link href="/">
<a>Go back to homepage</a>
</Link>
</h2>
</>
);
}
In a production environment, whenever Next.js detects the Link component, it automatically prefetches the content of the linked page in the background. This decreases the load time of the destination page when the user clicks the link.
You can also add third-party scripts to a Next.js page to introduce custom functionality to your application. Using the next/script component, you can perform optimized fetching and execution of third-party scripts. See the following code as an example:
import Script from 'next/script';
export default function MyFunc() {
return (
<>
<Head>
<title>Hello</title>
</Head>
<Script
src="https://platform.twitter.com/widgets.js"
strategy="lazyOnload"
onLoad={() =>
console.log(`script loaded correctly. `)
}
/>
</>
);
}
Next.js supports CSS modules, which can locally scope CSS by automatically defining a distinctive class name. This allows you to use the same class name across different files, without worrying about conflicts.
Let’s consider an example:
First create a new file named components/Button.module.css
with the following CSS:
.error {
color: white;
background-color: red;
}
Then you can import and use the module in a JS file like this:
import styles from './Button.module.css'
export function Button() {
return (
<button
type="button"
className={styles.error}
>
Destroy
</button>
)
}
(Code snippets courtesy of official Next.js documentation: https://nextjs.org/docs/basic-features/built-in-css-support)
You can choose between a single layout for your entire application or per-page layouts. If you are using multiple layouts, the getLayout function can help you get the component for a layout.
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
export default function Page() {
return {
/** add something here */
}
}
Page.getLayout = function getLayout(page) {
return (
<Layout>
<NestedLayout>{page}</NestedLayout>
</Layout>
)
}
(Code snippets courtesy of official Next.js documentation: https://nextjs.org/docs/basic-features/layouts)
Using server-side rendering, some of the HTML of a page gets rendered on the server before being sent to the browser. That decreases the time needed to display the first page on the client side, thus enhancing the user experience.
Using the getServerSideProps
function, you can implement server-side rendering for any page. For example:
// The server will call this function
export async function getServerSideProps({context}) {
// Get the data from the API
const data = await fetch(`MY_API`)
return { props: { data } }
}
function Page({ data }) {
// This will display the content to the user
return(
<div>{data}</div>
)
}
export default Page
Unlike other platforms, Next.js doesn’t require developers to write a lot of code or do several configurational tweaks to improve SEO. It packs several features that can optimize your website for search engines with little effort. Let’s look at some of them:
Since Next.js supports static file serving, we can create a robots.txt
file in the public folder of the root directory. For example, the following file will tell bots not to crawl /internal.
# Block all crawlers for /internal
User-agent: *
Disallow: /internal
# Allow all crawlers
User-agent: *
Allow: /
Using the getServerSideProps
function, you can dynamically generate an XML sitemap. You can also manually create a sitemap.xml
file inside the public directory.
<xml version="1.0" encoding="UTF-8">
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://www.sample.com/firstpage</loc>
<lastmod>2022-07-01</lastmod>
</url>
</urlset>
</xml>
The Head
component can be used to add metadata to pages.
import Head from 'next/head';
export default function MyFunc() {
return (
<>
<Head>
<title>Hello</title>
</Head>
<h1>Next app</h1>
</>
);
}
Using the robots
tag, you can assist search engines and bots in indexing your website. For example, the following tag will tell search engines to not index a page, and also not follow any links on it.
<meta name="robots" content="noindex,nofollow" />
You can also use the googlebot
tag to issue special instructions to Google.
<meta name="googlebot" content="noindex,nofollow" />
The Analytics dashboard lets you measure your website’s performance using core web vitals, the main metrics that gauge a user’s experience while visiting a website.
You can also send the aggregated data to a custom service or display it in your application logs. For example, use the following function to log the web vitals in real-time:
export function reportWebVitals(metric) {
console.log(metric);
}
Next.js Commerce is a comprehensive toolkit for developing performant e-commerce websites. Commerce integrates seamlessly with many e-commerce platforms, including Shopify, Vendure, Swell, BigCommerce, and OrderCloud. There are several demo sites built by the Next.js team which showcase how Commerce and these platforms work together:
You can set up a Commerce store with a few clicks directly from the official Next.js website. All you have to do is sign in to your GitHub account, create a Git repository, choose the platforms to integrate with, and click Deploy.
Commerce comes packed with several features that make it a great choice for building large e-commerce stores:
Next.js has developed a strong reputation among the developer community owing to its several programmer-friendly features. Here are some of them:
A live editing experience where developers can get instant feedback on edits made to components. If you are running v9.4 or newer, fast refresh will be enabled by default, making most edits visible within a second. Here are a few more neat things about fast refresh:
You can build your API routes with middleware, GraphQL, REST, and CORS. All you need to define an API route is to make a function default and pass the req (instance of http.IncomingMessage
) and res (instance of http.ServerResponse
) parameters to it. For example:
export default function handler(req, res) {
if (req.method === 'POST') {
// Process a POST request
} else {
// other HTTP methods are handled here
}
}
Another excellent way to decrease the initial loading time is by lazy loading external libraries and React components. For the former, you can use import()
, and for the latter, you can use next/dynamic
. In the following example, the header component won’t be a part of the initially loaded JavaScript bundle, and will be rendered only when the Suspense boundary gets resolved.
import dynamic from 'next/dynamic'
import { Suspense } from 'react'
const DynamicHeader = dynamic(() => import('../components/header'), {
suspense: true,
})
export default function myFunc() {
return (
<Suspense fallback={`Loading...`}>
<DynamicHeader />
</Suspense>
)
}
app
componentNext.js uses the app component to initialize pages by default. Developers can override app and implement a custom app. This can have several benefits:
componentDidCatch
module to implement customized error handlingBuilt-in support for environment variables allows you to use env.local
to load environment variables and expose them to the browser by adding a NEXT_PUBLIC_
prefix to them. A sample env.local
file can be:
…and then to access them in code:
export async function getStaticProps() {
const database = await database.connect({
host: process.env.DATABASE_HOST,
username: process.env.DATABASE_USER,
password: process.env.DATABASE_PASS,
})
// ...
}
It’s hard to think of too many cons of Next.js, but here are a couple:
Next.js is slowly becoming the staple of modern web architectures. It allows developers to fast-track the development of scalable, efficient, and user-friendly web applications. This post was meant to share all the things you need to get started with Next.js. To learn more, you can go through the extensive documentation available on the official website.
For more articles on using Next.js, read:
Or, check out our Next.js starter projects, Next.js headless CMS, and blog engine.