Building a NextJS backend with GraphQL and MongoDB

Stephany Doris
Women in Technology
5 min readDec 5, 2023
Photo by Scott Rodgerson on Unsplash

This article covers how to setup a nextjs application with both the client and backend. Our backend will be a graphql server integrated to MongoDB, which we’ll access on the client side as graphql apis. Before we start, let’s review the different stack used on this project

NextJS: serving as the official framework for ReactJS. For this project, we’ll leverage nextjs version 14, representing one of the latest releases in the framework

GraphQL: the querying language for our API, implemented using Apollo-GraphQL. Our backend will operate through a GraphQL server, managing our database’s read and write operations efficiently.

MongoDB: the data storage solution. We’ll utilize Mongoose, a robust MongoDB object modeling tool designed to streamline interactions with the database.

Note: this project assumes you have Node.js and npm installed on your system and a basic understanding of Next.js, GraphQL, and Apollo Server concepts.

Find the github repository here -> https://github.com/Stephany-Doris/NextJS-GraphQL-MongoDB-app

Project definition: We’ll create a backend api to support crud operations from a single page application, this includes create users with their details, fetch and display a list of users and also update and delete a user.

Project Setup

01. Initial setup using nextjs. You can update the app-name to anything you’d prefer.

npx create-next-app@latest nextjs-user-app

02. Install graphql and apollo packages

npm i graphql @apollo/client @apollo/server

03. Install Mongoose

npm i mongoose

04. Install apollo-datasource-mongodb. Official apollo data source for MongoDB. This package uses DataLoader for batching and per-request memoization caching.

npm i apollo-datasource-mongodb

05. Install as-integrations/next: this is an Apollo Server integration for use with Next.js that enables us to run apollo-server on nextjs api routes.

npm i @as-integrations/next

Note: you can clone the project on this url (https://github.com/Stephany-Doris/NextJS-GraphQL-MongoDB-app) and checkout the initial-setup branch to get the UI and packages installed during setup. You will need to run npm install after cloning and checking out to that branch.

Apollo graphql server initialization

Before we setup our apollo server let’s define a couple of things:

typeDefs: this is the schema or structure of the data accessible via our graphql api.

Resolvers: this determines how data requests for specific queries or mutations are resolved and returned.

We’ll begin by creating a route in our nextjs appdirectory. Create a new folder api and in that folder create another folder called graphql this will resolve to /api/graphql route on our browser. In the /graphql directory we’ll add the following route.ts , resolver.ts and schema.ts

Route.ts

In this file, we’re setting up Apollo Server to work with Next.js using the @as-integrations/next package. Here’s a breakdown of what’s happening in the code snippet below:

  • startServerAndCreateNextHandler: provided by the @as-integrations/next package, this is responsible for creating a handler that integrates Apollo Server with Next.js, accepting the Apollo Server instance and a configuration object as props.
  • ApolloServer: Imported from @apollo/server, this is used to instantiate an Apollo Server, passing in the defined resolvers and typeDefs
  • NextRequest: Imported from next/server, representing a Next.js server request.
  • typeDefs and resolvers: These contain the GraphQL schema (typeDefs) and resolver functions (resolvers) for the GraphQL API.
  • Handler Functions: Two functions (GET and POST) are exported, each accepting a NextRequest. These functions are designed to handle incoming HTTP requests (GET and POST) received by the Next.js server. Both functions utilize the handler created earlier, which encapsulates the logic for processing GraphQL requests through Apollo Server within Next.js context.

Schema.ts

Represents the schema definition for our GraphQL API supporting queries and mutations using specific input parameters.

Resolvers.ts

This file contains the functions that correspond to the defined queries and mutations in the schema. These functions will execute the necessary logic to retrieve or manipulate data from MongoDB and return the results as requested by the client’s queries or mutations. For now the code snippet below has not yet been integrated.

Integrate MongoDB

If you’re unfamiliar with how to create a mongodb database, visit the link below for a quick guideline. I find the easiest way to do this is using the mongodb atlas UI -> https://www.mongodb.com/basics/create-database

Once you’ve created your free cluster and created a database called user-db with a collection users we’ll proceed to connect our application to our database.

In this section, we’ll use your cluster’s connection string from the Atlas UI and connect the backend to your cluster.

For a detailed guideline on how to get your connection string, check out the link -> https://www.mongodb.com/docs/atlas/tutorial/connect-to-your-cluster/

We’ll update the route.ts file with the code snippet below to connect to the mongodb cluster using the connection string. Once you’ve saved your file restart your server npm run dev and navigate to the /api/graphql route on your browser, on your command line you should see the 🎉 connected to database successfully success message.

MongoDB Models:

To synchronize our database with our GraphQL schema, we’ll create a corresponding model, specifically for users. This model will mirror the fields outlined in our GraphQL schema.

MongoDB Data Source:

A MongoDB data source facilitates the interaction between our application and the MongoDB database. Using Mongoose’s create and find methods, we'll implement functionalities to create and retrieve all users respectively.

Let’s delve into the code.

Update our resolvers to return data from the mongodb database

Now that we’ve set up our models and the logic to retrieve and manipulate data from our database, we’ll update our resolvers to use this functions when querying data or mutations.

Note: update the following in your route.ts file, in order to access datasource via context.

import Users from "./datasources";
import UserModel from "./models";

const handler = startServerAndCreateNextHandler<NextRequest>(server, {
context: async (req, res) => ({
req,
res,
dataSources: {
users: new Users({ modelOrCollection: UserModel }),
},
}),
});

And with that we are able to create users and query our users from our database. You should be able to test this out on the playground on route localhost:3000/api/graphql

If you’d like to review the methods to update and delete a user, checkout the main branch and test the same on your playground url. I’ve also added the client integration that you can interact with on localhost:3000

Conclusion

We’ve laid the groundwork for our Next.js application incorporating both frontend and backend elements. By setting up Next.js, integrating GraphQL with Apollo Server, and connecting to MongoDB using Mongoose, we’ve established a foundation for handling user-related operations within our application.

Should you wish to build on this, you can always expand the GraphQL schema, implement additional resolvers, and enhance database interactions to support additional functionalities.

I hope you learnt a lot. Feel free to connect with me on LinkedIn and shoot me a dm if you have any questions. Am also always willing to collaborate on anything GraphQL :)

--

--

Stephany Doris
Women in Technology

Writing about The Web, Performance and Standards | Software engineer