Building SEO-Friendly Web Applications with Next.js and MongoDB

Boost your SEO rankings with Next.js and MongoDB, and take advantage of built-in features like server-side rendering, static site generation and API routes.

Leandro Ercoli
7 min readMar 21, 2023

Next.js is a powerful framework built on top of React that offers several benefits. It provides built-in support for server-side rendering (SSR), static site generation (SSG), and API routes. SSR generates the HTML page on the server and sends it to the client, which significantly reduces the page loading time, making it faster and more SEO-friendly. SSG pre-generates the HTML pages at build time, which means that the server does not have to generate them every time a user requests a page, improving the page loading time and reducing server costs.

Additionally, Next.js API routes simplify the creation of server-side endpoints that can be called by your client-side code, allowing you to perform server-side operations such as database queries or file system access. Overall, Next.js offers a variety of built-in features for building web applications that make it easier to create fast and scalable web applications with React.

Just want the code? Clone this Next.js template which includes MongoDB integration and an example for server-side rendering (SSR).

Setting up Next.js with TypeScript and MongoDB

To set up a new Next.js project with TypeScript, you can use the create-next-app command with the --typescript flag:

npx create-next-app@latest --typescript my-next-app

This will create a new Next.js project with TypeScript support. You can then navigate to the project directory and start the development server with the following commands:

cd my-next-app
npm run dev

Install the mongodb package using npm or yarn:

npm install mongodb

yarn add mongodb

Create a new file called mongodb.ts in the lib directory. Import the MongoClient class from the mongodb package and define a new async function called connectToDatabase that will connect to the MongoDB database. This function should return a new instance of the MongoClient class.

import { MongoClient } from "mongodb";

const MONGODB_URI = process.env.MONGODB_URI;

export async function connectToDatabase() {
if (!MONGODB_URI) {
throw new Error("Add Mongo URI to .env.local");
}

const client = new MongoClient(MONGODB_URI);
return client.connect();
}

Note that this example assumes that you have an environment variable called MONGODB_URI that contains the connection string for your MongoDB database. You will need to modify the code to match the name of your environment variable and the format of your connection string.

To set up environment variables in your Next.js project, you can create a .env.local file in the root of your project. Next.js will automatically load the environment variables from this file into the process.env object. You can then access the environment variables in your code using process.env.VAR_NAME

For example, if you want to set an environment variable API_KEY to https://my-api.com, you can add the following line to your .env.local file:

API_KEY=foo-bar-123456 
NEXT_PUBLIC_API_URL=https://my-api.com # will be accessible from the browser

Note that if you want to access the environment variables in the browser, you must prefix the variable name with NEXT_PUBLIC_. For example, if you want to access the API_URL variable in the browser, you can use process.env.NEXT_PUBLIC_API_URL.

Creating Pages

After setting up the application, it’s time to start creating pages. Next.js uses a file-system based routing system, which means that each page is a file with its own URL. Simply create a new file in the pages directory with the desired URL path, and Next.js will automatically generate the page.

To create a homepage that displays data from an API in Next.js, you can follow these steps:

  1. Create a new file named index.tsx in the pages directory that exports a default React component.
  2. Define a new state variable data using the useState hook. Use the useEffect hook to fetch the data from the API and update the data variable when the component loads.
  3. Render the data in a component using JSX.
import { useState, useEffect } from 'react';

type Item = {
id: string;
title: string;
description: string;
}

function HomePage() {
const [data, setData] = useState<Item[]>([]);

useEffect(() => {
async function fetchData() {
const response = await fetch('<https://my-mock-api.com/data>');
const data = await response.json();
setData(data);
}

fetchData();
}, []);

return (
<div>
{data.map((item) => (
<div key={item.id}>
<h2>{item.title}</h2>
<p>{item.description}</p>
</div>
))}
</div>
);
}
export default HomePage;

Note that this example assumes that the API returns an array of objects with id, title, and description properties. You will need to modify the code to match the format of your own API.

Need an API? Try this one — it returns data from over 28k operational airports and landing strips in the world!

Creating an API route

One of the powerful features of Next.js is the ability to create API routes. This allows you to create server-side endpoints that can be called by your client-side code to fetch data, either from the server or from a third-party API.

One advantage of using a Next.js API route instead of calling a third-party API directly from the client is that it adds an extra layer of security. By proxying the request through your own server, you can ensure that sensitive API keys and other authentication information are not exposed to the client. Additionally, you can add rate limiting or other security measures to prevent abuse of the API.

To create an API route in Next.js, simply create a new file in the pages/api directory with the desired endpoint name. For example, if you want to create an endpoint at https://my-next-app.com/api/users, you would create a file at pages/api/users.ts.

Inside the file, you must export a default handler function that will take care of the API request and return the data to the client. You can use API routes to perform server-side operations such as database queries or file system access, or to mask the URL of an external service and hide environment variables.

Here’s an example of how you might use the connectToDatabase function in an API route to access a MongoDB database:

import { connectToDatabase } from "@/lib/mongodb";
import { NextApiRequest, NextApiResponse } from "next";

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
// Validate the request method
if (req.method !== "GET") {
res.status(405).send({ message: "Only GET requests allowed" });
return;
}

const client = await connectToDatabase();
const db = client.db("local");

const allPosts = await db.collection("users").find().toArray();

res.json({ status: 200, data: allPosts });
}

In this example, we define a handler function from where we will establish a connection to the MongoDB database. We then call the find() method on the users collection to retrieve all the documents in the collection. Finally, we return the data as a JSON response with a 200 status code.

Pre-rendering pages in Next.js with getServerSideProps

Next.js supports server-side rendering (SSR) using the getServerSideProps function. This function runs on the server and fetches data that will be used to pre-render the page. This can be useful for pages that require dynamic data that cannot be pre-rendered at build time (static site generation).

Here’s an example of how you might use the getServerSideProps function to pre-render a page that displays data from a MongoDB collection:

import { connectToDatabase } from "@/lib/mongodb";
import { GetServerSideProps } from "next";

type Post = {
id: string;
title: string;
content: string;
}

type Props = {
posts: Post[];
}

// This code runs server side, so we can use the database connection directly.
// The page will be pre-rendered with the data returned from the database.
export const getServerSideProps: GetServerSideProps<Props> = async () => {
const client = await connectToDatabase();
const db = client.db("local");

// Get all documents from the posts collection
const posts = await db.collection("posts").find().toArray();

return {
props: {
posts: JSON.parse(JSON.stringify(posts)), // Data must be serialized
},
};
};

export default function PostsPage({ posts }: Props) {
return (
<div>
<h1>Posts</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>
<h2>{post.title}</h2>
<p>{post.content}</p>
</li>
))}
</ul>
</div>
);
}

Note that we need to use JSON.parse(JSON.stringify(posts)) to convert the posts array to a JSON string and then back to a JavaScript object. This is necessary because the posts array contains ObjectId instances, which cannot be serialized directly to JSON.

Deploying a Next.js Application to Vercel

Vercel is a popular platform for deploying Next.js applications. It offers a simple and easy-to-use interface for deploying and managing your applications. To deploy a Next.js application to Vercel, follow these steps:

  1. Sign up for a free Vercel account.
  2. Connect your GitHub, GitLab, or Bitbucket account to Vercel.
  3. Create a new project in Vercel and link it to your Git repository.
  4. Configure your project settings, including environment variables and build options.
  5. Deploy your project to Vercel.

With Vercel, you can also set up automatic deployments, preview URLs, and custom domains. Vercel also provides built-in performance analytics, so you can monitor the performance of your application.

In this article, we have explored how to build a full-stack project with Next.js and MongoDB. We have seen how Next.js provides several benefits over React, including support for SSR and SSG. We have also seen how to create API routes in Next.js to fetch data from a database like MongoDB, that provides a flexible and powerful database solution that can handle large amounts of data.

With these tools, you can easily build dynamic web applications that are fast, scalable, and SEO-friendly. If you’re new to Next.js, I recommend checking out the official Next.js documentation and tutorials to learn more about its features and capabilities.

--

--

Leandro Ercoli

Computer Engineer — Full-stack web developer and multi-platform mobile developer