Next.js is a popular React-based framework for building server-side rendered (SSR) and statically generated websites and applications. With Next.js, you can create a fullstack app that includes a frontend and a backend.
Next.js provides built-in support for MongoDB, allowing you to easily connect your frontend to a MongoDB database. This makes it a great choice for building fullstack apps that require real-time data synchronization.
Using Next.js and MongoDB together can help you build a fullstack app that's fast, scalable, and easy to maintain. By leveraging the strengths of both technologies, you can create a seamless user experience that's both efficient and enjoyable.
Getting Started
To create a Next.js application, run the command `npx create-next-app next-mongodb --example with-mongodb` in your terminal. This command will create a new Next.js application in the folder next-mongodb.
You can use the `--use-npm` or `--use-pnpm` flags to explicitly use NPM or PNPM as the package manager instead of Yarn.
The command above will create a new Next.js application in the folder next-mongodb. Following, you install all the required dependencies by running the command `npm install` or `yarn install` in the terminal.
You can also use a one-time command to create a MongoDB Next.js basic project. Run `npx create-next-app --example with-mongodb` to bootstrap the application. This will create an application ready and configured with all dependencies needed to access MongoDB.
To create a Next.js project, create a directory for a new project and cd into it. Then, run `npm install mongoose` or `yarn add mongoose` to install Mongoose as a dependency.
Create a new .env file in the root directory of your project to hold your database connection string. Finally, go ahead and spin up the development server to update the changes and navigate to http://localhost:3000 in your browser.
Front-End App
The front-end app of a Next.js and MongoDB full-stack application is built with React and contains several key pages. The home page is a secure page that displays a welcome message to the logged-in user.
The app includes a login page, a registration page, and a users list page. The login and registration pages are public, while the users list page is secure and requires authentication. The users list page also includes options to add, edit, or delete users.
The app's navigation and layout are handled by the Secure Layout Component, which redirects unauthenticated users to the login page. The users list page and edit user page use a simple bootstrap loading spinner component to display a loading animation while data is being fetched.
assistant
The assistant in the Next.js front-end app is the Secure Layout Component, which redirects unauthenticated users to the login page.
The Secure Layout Component is used to protect secure pages in the app, such as the home page and the users list page. This component ensures that only authenticated users can access these pages.
The app also uses a simple bootstrap loading spinner component, used by the users list page and edit user page.
The Next.js API handler is a wrapper function for all API route handlers in the /app/api folder, enabling adding global middleware to the Next.js API request pipeline and adding support for global exception handling.
The API handler accepts a handler object that contains a method for each HTTP method that is supported by the handler, such as GET, POST, PUT, and DELETE.
If a request is received for an unsupported HTTP method, the API handler returns a 405 Method Not Allowed response.
Here are the supported HTTP methods in the API handler:
- GET
- POST
- PUT
- DELETE
The API handler also uses the global JWT middleware for security, which handles authentication and authorization for all secure routes in the Next.js API.
Back-End
The Next.js API is the backbone of a full-stack application, and it's where the magic happens. It contains several routes/endpoints that handle user authentication, registration, and data retrieval.
The API has public routes for authenticating and logging out users, which are protected by a JWT token. These routes are /api/account/login and /api/account/logout respectively.
Here are the secure routes that require a valid JWT token: /api/users, /api/users/[id], /api/users/[id] (PUT), and /api/users/[id] (DELETE).
These secure routes are used to retrieve, update, and delete user data. The /api/users route returns all users, while the /api/users/[id] route returns a specific user by their ID.
The /api/users/[id] route also allows updating a user's data, and the /api/users/[id] (DELETE) route deletes a user entirely.
Database Setup
Database Setup is a crucial step in building a full-stack application with Next.js and MongoDB. To get started, you can quickly spin up a MongoDB database by configuring a MongoDB cluster in the cloud for free.
You'll need to copy the database connection URI string once you have your database up and running. This string will be used to connect to your MongoDB database.
To create a Next.js application with a MongoDB setup, you can use a one-time command that lets you create a MongoDB Next.js basic project. This will create an application ready and configured with all dependencies needed to access MongoDB.
Here are the steps to create a Next.js application with MongoDB setup:
- Proceed to your preferred working directory.
- Run the following command: `npx create-next-app --example with-mongodb posts_app`
- Choose your package manager: Yarn, NPM, or PNPM.
Once you've created your Next.js application, you'll need to set up a Mongoose connection to your MongoDB database. This will allow you to interact with your MongoDB database using Mongoose's Object Data Modeling (ODM) library.
To set up a Mongoose connection, you'll need to install Mongoose as a dependency and create a new .env file to hold your database connection string.
User Management
User Management is handled through the user service, a React hook that encapsulates client-side logic and handles HTTP communication between the React front-end and the Next.js back-end API for everything related to users.
The user service contains methods for logging in and out of the app, registering a new user, and standard CRUD methods for retrieving, creating, and updating user data. HTTP requests are sent with the help of the useFetch hook.
Zustand is used internally by the user service to manage shared state properties, allowing any component in the application to access users, user, and currentUser properties. The users list page displays all users by calling userService.getAll() on load and reading the userService.users property.
On successful login, the returned user is stored in browser local storage to keep the user logged in between page refreshes. The user property exposes an RxJS Observable that notifies components when a user logs in, logs out, or updates their profile.
Registration Form
The registration form on the Next.js page is built with the React Hook Form library, which includes fields for first name, last name, username, and password.
When the form is submitted and valid, the onSubmit function gets called, and it submits the form data to the Next.js API by calling userService.register().
The registration form uses the React Hook Form library, which provides a simple way to build forms in React applications.
The onSubmit function is triggered when the form is submitted and valid, ensuring that the data is sent to the API correctly.
Joi is used for schema validation in Next.js API, which includes validating data sent in HTTP requests, such as the register route.
User Service
The user service is a React hook that encapsulates client-side logic and handles HTTP communication between the React front-end and the Next.js back-end API for everything related to users.
It contains methods for logging in and out of the app, registering a new user, and standard CRUD methods for retrieving and updating user data. HTTP requests are sent with the help of the useFetch hook.
Zustand is a light-weight React state management library used internally by the user service to manage shared state properties so they can be accessed by any component in the application.
For example, the users list page displays all users by calling userService.getAll() on load and reading the userService.users property.
TypeScript interfaces are used to define the properties and methods of a user object, the zustand user state store, and the user service.
The user service interface extends the user store interface to include the shared state properties in service interface.
On successful login, the returned user is stored in browser local storage to keep the user logged in between page refreshes.
The user property exposes an RxJS Observable so any component can subscribe to be notified when a user logs in, logs out or updates their profile.
The userValue getter allows other components to easily get the current value of the logged in user without having to subscribe to the user observable.
The user service handles communication between the React front-end and the backend API for everything related to users.
It contains methods for logging in and out of the app, registering a new user, and standard CRUD methods for retrieving and updating user data.
The register page contains a simple registration form built with the React Hook Form library with fields for first name, last name, username and password.
The onSubmit function gets called when the form is submitted and valid, and submits the form data to the Next.js API by calling userService.register().
Authenticate
The authenticate route in Next.js API receives HTTP POST requests sent to /api/users/authenticate, containing a username and password which are authenticated by the authenticate() function.
This route supports HTTP POST requests by passing an object with a post() method to the apiHandler() which is mapped to the authenticate() function.
Security for this route is handled by the global JWT middleware.
The login page form built with the React Hook Form library contains username and password fields for logging into the Next.js tutorial app.
The onSubmit function gets called when the form is submitted and valid, and submits the user credentials to the API by calling userService.login().
The authenticate handler receives HTTP requests sent to the authenticate route /api/users/authenticate and supports HTTP POST requests containing a username and password which are authenticated by the authenticate() function.
The request schema for the login route is defined with the joi data validation library and assigned to the login.schema property.
Application Pages
In Next.js, pages are React components that serve as routes on the browser. The pages folder is a special directory that treats files as routes, and every page has a route mapped to it based on its file name.
To implement pages for CRUD operations, you'll need to create a posts directory inside the pages folder. This directory will host files for managing posts.
The posts directory should contain the following files:
- index.tsx: the home page showing added posts
- add.tsx: a file for adding new posts
- [id].tsx: a file for updating specific posts
These files will be used to render forms, display added posts, and update existing posts.
Data Context
The MongoDB data context is a crucial part of any Next.js and MongoDB full-stack application. It allows you to connect to MongoDB using Mongoose and exports an object containing all of the database model objects in the application.
This makes it easy to read and write to any part of the database from a single point. The database connection string is defined in the .env file as the MONGODB_URI environment variable.
To establish a connection, you'll need to define the database connection string in your .env file. This is where the MONGODB_URI environment variable comes in, providing the necessary information for the MongoDB data context to connect to your database.
The MongoDB data context is used to export an object containing all of the database model objects in the application. Currently, this includes the User model, which is a great starting point for your application.
By using the MongoDB data context, you can simplify your data access and manipulation, making it easier to manage your application's data. This is especially useful when working with complex data models and relationships.
Tools and Middleware
To develop and run Next.js + MongoDB applications locally, you'll need Node.js and npm, which includes the Node runtime and command line tools. Visual Studio Code is also required, although you can use a different code editor if you prefer.
You'll also need access to a running MongoDB server instance, which can be remote or on your local machine. To get started, download MongoDB from the MongoDB Community Server downloads page at https://www.mongodb.com/download-center/community. Alternatively, you can run MongoDB in a Docker container using the official docker images available at https://hub.docker.com/_/mongo.
To ensure MongoDB is started so the app can connect to it, follow the instructions on the MongoDB install page for your operating system, available at https://docs.mongodb.com/manual/administration/install-community/.
Tools Required
To develop and run Next.js + MongoDB applications locally, you'll need the following tools.
Node.js and npm are required, which includes the Node runtime and command line tools. This is a must-have for any Next.js development.
Visual Studio Code is a popular code editor that runs on Windows, Mac, and Linux. You can use it if you prefer, or stick with your current code editor.
MongoDB is necessary for the Next.js app to connect to a running server instance. You can access a remote instance or set up one on your local machine. The MongoDB Community Server is free and available for download at https://www.mongodb.com/try/download/community.
You can also run MongoDB in a Docker container, using the official docker images available at https://hub.docker.com/_/mongo.
Here are the tools you need in a concise list:
- Node.js and npm
- Visual Studio Code
- MongoDB (local or remote)
Ensure MongoDB is started so the app can connect to it. Instructions for installing MongoDB on each OS are available at https://docs.mongodb.com/manual/administration/install-community/.
JWT Middleware
JWT Middleware is used to validate JWT tokens in requests sent to protected API routes.
The JWT middleware verifies the token by using the auth helper if the request is to a secure API route, and bypasses public routes.
An error is thrown if the token is invalid, causing the global error handler to return a 401 Unauthorized response.
The current user id is added to the request headers, making it accessible to other code in the request.
The JWT middleware is added to the Next.js request pipeline in the API handler wrapper function.
The register and authenticate routes are made public by passing them to the unless() method of the express-jwt library.
Code and Setup
To set up a Next.js app with MongoDB, start by running a one-time command in your preferred working directory. This command uses the `npx create-next-app` command with the `--example with-mongodb` flag to create a template application with a ready-to-use MongoDB setup.
The default package manager used is Yarn, but you can choose your preferred package manager by adding the `--use-npm` or `--use-pnpm` flag to the command. This will instruct the CLI to use the specified package manager to generate the project.
To create the project, you'll need to run the following command: `npx create-next-app posts_app --example with-mongodb`. This will create a directory named `posts_app` in your current working directory, containing the basic structure for a Next.js app with MongoDB.
App Setup
To set up your Next.js app, start by running a one-time command in your preferred working directory. This command, `npx create-next-app`, will create a Next.js application with a MongoDB setup, using Yarn as the default package manager.
You can also use other package managers like NPM or PNPM by adding flags to the command. For example, using NPM would be `--use-npm`, while using PNPM would be `--use-pnpm`.
Next, create a directory for your new project and navigate to it. Once you've done this, you can install Mongoose as a dependency.
To hold your database connection string, create a new `.env` file in the root directory of your project. You'll also need to copy your MongoDB connection URI, which you can obtain by setting up a MongoDB database or configuring a MongoDB cluster in the cloud.
To connect your Next.js app to MongoDB, you'll need to rename `.env.local.example` to `.env.local` and paste in your MongoDB connection URI.
Code Documentation
Code Documentation is a crucial part of any project, and in Next.js, it's especially important to keep your code organized and easy to understand.
The Next.js project structure is designed to make it easy to find what you need, with clear and consistent naming conventions.
Private folders, marked by a leading underscore, are ignored by the Next.js routing system. This means you can keep your React components and helpers in these folders without worrying about them being exposed to the public.
Here are the main folders you'll find in a Next.js project:
- _components: React components used by pages or other React components.
- _helpers: Front-end React helpers, server-side helpers, and API specific helpers.
- _services: Services that encapsulate client-side logic and handle HTTP communication.
Public pages, like the login and register pages, are found in the (public) folder, which is marked as a Route Group to keep them out of the URL path. Secure pages, accessible only to authenticated users, are in the (secure) folder, also marked as a Route Group.
Repo
In a Next.js application, you'll likely need to set up a MongoDB repository to handle user data. The users repo encapsulates all access to user data stored in MongoDB.
It exposes methods for authentication and standard CRUD operations for reading and managing user data. The repo is used on the server-side by the Next.js users API route handlers.
A MongoDB users repo is created to handle user data, and it's used on the server-side by Next.js users API route handlers. These handlers include authenticate.js, register.js, [id].js, and index.js.
To set up a MongoDB repository, you'll need to write a script to connect and save the connection as illustrated in the lib/mongodb.ts file. This script creates a client that connects to your database and saves the connection created.
Here's a list of steps to install MongoDB dependencies and write a script to connect and save the connection:
- Install MongoDB dependencies to your project
- Write a script to connect and save the connection as illustrated in the lib/mongodb.ts file.
Frequently Asked Questions
Is Next.js considered full stack?
Next.js is considered a full-stack framework, but it doesn't cover every aspect of back-end development, such as database systems. You'll still need to set up a separate database provider to complete your full-stack setup.
Is MongoDB full stack?
No, MongoDB is not a full stack, but it's often used as a core database in popular technology stacks like MEAN and MERN.
Is Next.js frontend or backend?
Next.js is primarily a frontend framework, but it also has server-side capabilities. Its backend features are not as robust as specialized backend frameworks.
Sources
- https://jasonwatmore.com/next-js-13-app-router-mongodb-user-rego-and-login-tutorial-with-example
- https://pieces.app/blog/building-a-fullstack-application-with-next-js-and-mongodb
- https://blog.openreplay.com/a-complete-guide-to-nextjs-plus-mongodb/
- https://www.makeuseof.com/nextjs-mongodb-mongoose-data-management-store-fetch/
- https://jasonwatmore.com/next-js-13-mongodb-user-registration-and-login-tutorial-with-example-app
Featured Images: pexels.com