Docs Menu

Docs HomeDevelop ApplicationsAtlas Device SDKs

Next.js Integration Guide - Web SDK

On this page

  • Before You Begin
  • Add Authentication
  • Client-Side Rendering
  • Server-Side Rendering
  • Static Rendering
  • Alternate Ways to Query MongoDB from Next.js

The following guide explains how to integrate the Realm Web SDK into a Next.js application. You can use the Realm Web SDK to access data in MongoDB Atlas from web apps, such as those made with Next.js. The Realm Web SDK interfaces with your data in MongoDB Atlas via Atlas App Services. Next.js is a React-based web framework that handles app configuration and structure, and supports client-side, server-side, and static rendering.

The Realm Web SDK supports all of these rendering modes in Next.js:

  • Client-side rendering: Query MongoDB directly from the browser using the Atlas GraphQL API or MongoDB Data Access.

  • Server-side rendering: Authenticate users with App Services from the browser and query using the GraphQL API on the server

  • Static rendering: Fetch data from MondoDB Atlas to generate pages at build time.

Before using this integration guide, you should:

Tip

MongoDB Atlas Vercel Integration

If you're using Vercel to host your Next.js app, add the MongoDB Atlas integration to easily connect your Next.js app to Atlas.

Learn more about the Vercel MongoDB Atlas integration.

Before you can query MongoDB from your app, you must initialize the App Services client and authenticate a user. You can follow the steps below to connect the Realm Web SDK to client-side Next.js.

In this example, we're going to expose an authenticated Realm.App instance throughout the app using Realm.getApp() in a custom React Hook.

Tip

See also:

For additional ways to expose Realm authentication throughout your application, refer to the Next.js authentication documentation.

1

Use the App ID to connect the Next.js app to Atlas App Services. Expose the App ID throughout the app as an environment variable by doing the following:

  1. Find Your App ID.

  2. Create the file .env.local in the project's root directory.

  3. Add an environment variable for the App ID. To make the App ID accessible from the browser in addition to the server, preface its name with NEXT_PUBLIC_.

.env.local
NEXT_PUBLIC_APP_ID=<YOUR App Services App ID>
2

The client uses a React Hook to instantiate and access the Realm.App, which you use to connect to App Services using the App ID. You will use this hook throughout the pages you create in this guide.

  1. Create the file components/useApp.js.

  2. Add the following code to instantiate and access the App instance:

components/useApp.js
import { useEffect, useState } from "react";
import * as Realm from "realm-web";
export function useApp() {
const [app, setApp] = useState(null);
// Run in useEffect so that App is not created in server-side environment
useEffect(() => {
setApp(Realm.getApp(process.env.NEXT_PUBLIC_APP_ID));
}, []);
return app;
}
3

Now you can access the app instance with the useApp() hook, and use it to log a user in. Authenticate anonymously in pages/index.js when a user arrives to the app home page.

import { useEffect } from "react";
import * as Realm from "realm-web";
import Link from "next/link";
import { useApp } from "../components/useApp";
export default function Home() {
const app = useApp();
// note: useEffect runs in the browser but does not run during server-side rendering
useEffect(() => {
// If no logged in user, log in
if (app && !app.currentUser) {
const anonymousUser = Realm.Credentials.anonymous();
app.logIn(anonymousUser);
}
}, [app, app?.currentUser]);
return (
//Your app
);
}

In a real application, you would want to have a more complex authentication flow. For more information, refer to the Next.js authentication documentation.

This section shows how you can integrate Next.js client-side rendering with the Realm Web SDK. Following these steps, you can directly query MongoDB and interact with an Atlas App Services serverless backend through client-side JavaScript in your Next.js application. You can query MongoDB using either MongoDB Data Access or the Atlas GraphQL API.

Once the App client is initialized and a user is authenticated, you can use MongoDB Data Access to query MongoDB directly from client code in your application.

Access the MongoDB Data Access interface from the app object with App.User.mongoClient(), and then use it to query MongoDB.

import { useEffect, useState } from "react";
import { useApp } from "../components/useApp";
function MongoDbDataAccess({ name }) {
const [plant, setPlant] = useState();
const app = useApp();
useEffect(() => {
if (app?.currentUser) {
const mongo = app?.currentUser?.mongoClient("mongodb-atlas");
const plants = mongo.db("example").collection("plants");
plants.findOne({ name }).then((foundPlant) => {
setPlant(foundPlant);
});
}
}, [app, app?.currentUser, app?.currentUser?.id, name]);
return (
<div>
<h1>Data from MongoDB Access</h1>
{plant ? (
<div>
<p>{plant.name}</p>
<p>{plant.color}</p>
</div>
) : (
"no plant"
)}
</div>
);
}
export default function DaffodilInformation() {
return <MongoDbDataAccess name="daffodil" />;
}

Alternatively, you can use the Atlas GraphQL API to query MongoDB via GraphQL from Next.js client-side code.

This example uses the Apollo GraphQL client to execute GraphQL queries. Install the Apollo client with its npm package @apollo/client and its peer dependency graphql.

npm install @apollo/client graphql

Now you can add a page to perform GraphQL queries. The code in the page does the following:

  1. Imports the necessary dependencies

  2. Creates the GraphQL client in a provider component.

  3. Defines the GraphQL query.

  4. Creates a component that consumes the GraphQL provider and runs the query.

  5. Exports the provider component wrapping the consumer component.

All together, the GraphQL page should look as follows:

// 1. Import dependencies
import {
ApolloClient,
ApolloProvider,
HttpLink,
InMemoryCache,
useQuery,
gql,
} from "@apollo/client";
import { useApp } from "../components/useApp";
// 2. Add GraphQL client provider
function GraphQLProvider({ children }) {
const app = useApp();
const client = new ApolloClient({
link: new HttpLink({
uri: process.env.NEXT_PUBLIC_GRAPHQL_API_ENDPOINT,
// We get the latest access token on each request
fetch: async (uri, options) => {
const accessToken = app.currentUser?.accessToken;
options.headers.Authorization = `Bearer ${accessToken}`;
return fetch(uri, options);
},
}),
cache: new InMemoryCache(),
});
return <ApolloProvider client={client}>{children}</ApolloProvider>;
}
// 3. GraphQL query
const GET_PLANT = gql`
query Plant($name: String!) {
plant(query: { name: $name }) {
_id
sunlight
name
color
type
_partition
}
}
`;
// 4. Consumer of provider and query
function PlantInformation({ name }) {
const { loading, error, data } = useQuery(GET_PLANT, {
variables: { name },
});
if (loading || !data) return <p>Loading ...</p>;
if (error) console.error("Failed with error:", error);
return (
<div>
{data.plant ? (
<div>
<p>{data.plant.name}</p>
<p>{data.plant.color}</p>
</div>
) : (
"no plant"
)}
</div>
);
}
// 5. Export page with the GraphQL query
export default function FullGraphQLPage() {
return (
<GraphQLProvider>
<PlantInformation name="daffodil" />
</GraphQLProvider>
);
}

Tip

For more information on querying Atlas with the GraphQL API with React, refer to the Apollo Client (React) documentation.

This section shows how you can integrate Next.js server-side rendering with the Realm Web SDK. Using the Realm Web SDK with server-side rendering allows you to access data as a specific user. In doing so, you apply App Services Rules and Permissions to those user queries.

To query MongoDB Atlas directly from the Next.js server, you must set up two different components: Atlas GraphQL API on the Next.js server and the Realm Web SDK in the browser.This section explains the setup of both.

You may want to integrate the Web SDK and Next.js because it allows you to:

  • Access data stored in Atlas directly on page load.

  • Apply Atlas App Services rules and permissions to requests to reduce server-side code.

  • Reduce use of client-side JavaScript.

  • Perform server-side data manipulation.

On a high level, the process for using the Realm Web SDK with Next.js server-side rendering is as follows:

  1. In the browser, create a instance of your App Services client and log in a user. Save the user's accessToken as a cookie. This examples uses the package nookies, which simplifies cookie management in a Next.js app.

  2. On the server, parse the accessToken cookie and use it to fetch data from MongoDB using the Atlas GraphQL API.

  3. On the server, pre-render the data from MongoDB in your webpage before sending it to the browser.

Note

Do Not Use MongoDB Data Access with Server-side Rendering

While possible to use the MongoDB Data Access in server-side environments to query MongoDB, it is not generally advisable. You would need to persist user credentials in the browser to pass to the server on every request, which is a security vulnerability. Plus, MongoDB Data Access makes requests from a user object, which would need to be re-instantiated and re-authenticated on every request.

The following steps outline using the Realm Web SDK with Next.js server-side rendering.

1

Install the following npm packages:

npm install nookies
npm install @apollo/client graphql
2

Create a custom App page wrapper. Create the file pages/_app.js, and get the Realm.App instance with the useApp() hook.

If there is a user currently authenticated, save their accessToken as a cookie. This transfers the accessToken from the browser to the server on every request. Set your cookie in a useEffect hook that runs every time there's a change in the user object, as shown below. The setInterval also resets the credential in cookies before the token expires.

import { useApp } from "../components/useApp";
import { setCookie } from "nookies";
// Import the useEffect hook
import { useEffect } from "react";
function MyApp({ Component, pageProps }) {
const app = useApp();
// Reset the user access token in cookies on a regular interval
useEffect(() => {
const user = app?.currentUser;
if (user) {
setCookie(null, "accessToken", user.accessToken);
// Refresh token before session expires
const TWENTY_MIN_MS = 1200000;
const resetAccessToken = setInterval(async () => {
await app?.currentUser?.refreshCustomData();
setCookie(null, "accessToken", user.accessToken);
}, TWENTY_MIN_MS);
// Clear interval setting access token whenever component unmounts or
// there's a change in user.
return () => clearInterval(resetAccessToken);
}
}, [app, app?.currentUser]);
return (
<>
<Component {...pageProps} app={app} />
</>
);
}
export default MyApp;
3

Create a new page file to perform the server-side rendering. On the page, add code to perform the following:

  1. Import the relevant dependencies.

  2. Add a function that creates a server-side GraphQL client on every request with the user's current auth token.

  3. Create the GraphQL request which the server uses to fetch data.

  4. Use the Next.js getServerSideProps function to perform the following:

    1. Parse access token from cookies.

    2. Create a GraphQL client with the access token.

    3. Run the GraphQL query.

    4. Return data to be used in the server-side render.

  5. Export the page component to render the data.

All together, the server-side rendering page looks as follows:

// 1. import dependencies
import nookies from "nookies";
import { ApolloClient, InMemoryCache, HttpLink, gql } from "@apollo/client";
// 2. Function to create GraphQL client
const createClient = (token) =>
new ApolloClient({
link: new HttpLink({
ssrMode: true,
uri: process.env.NEXT_PUBLIC_GRAPHQL_API_ENDPOINT,
headers: {
Authorization: `Bearer ${token}`,
},
}),
cache: new InMemoryCache(),
});
// 3. GraphQL Query used in SSR
const GET_PLANT = gql`
query Plant($name: String!) {
plant(query: { name: $name }) {
_id
sunlight
name
color
type
_partition
}
}
`;
// 4. Server-side logic to parse cookie and run query
export async function getServerSideProps(context) {
const { accessToken } = nookies.get(context);
const client = createClient(accessToken);
const {
data: { plant: lily },
} = await client.query({
query: GET_PLANT,
variables: { name: "daffodil" },
});
return {
props: { lily },
};
}
// Full page exported that gets the data from SSR
export default function Ssr({ lily }) {
return (
<div>
<h1>Data from Server-Side Rendering</h1>
{lily ? (
<div>
<p>{lily.name}</p>
<p>{lily.color}</p>
</div>
) : (
"no plant"
)}
</div>
);
}

You can use Next.js static rendering with the Realm Web SDK to pull data from MondoDB Atlas and generate page HTML at build time.

You might want to use the Realm Web SDK with static rendering for the following use cases:

  • Pull in content management system data

  • Add configuration information

  • Create internationalized content

1

You need to create a Server API key for authentication. Follow the steps on the API Key Configuration page to complete this step. Then, in your Next.js app, add the API key to your .env.local file. The variable stored is not accessible from the browser, as long as you do not prefix it with PUBLIC_NEXT_.

.env.local
REALM_API_KEY=secret_api_key

Now you can access the variable in your app, except for in client-side rendering.

const { REALM_API_KEY } = process.env;
2

You can use the Next.js function getStaticProps() to query MongoDB during static generation.

In order to pre-render your page using getStaticProps(), connect your Next.js app to the Realm Web SDK. Then, you can use getStaticProps() to fetch data from MongoDB. The following example shows how to query MongoDB with static rendering.

import * as Realm from "realm-web";
export async function getStaticProps() {
const apiKey = process.env.REALM_API_KEY;
const app = new Realm.App({ id: process.env.NEXT_PUBLIC_APP_ID });
// Log in user using realm API key
const credentials = Realm.Credentials.apiKey(apiKey);
const user = await app.logIn(credentials);
// Connect to database
const mongo = user.mongoClient("mongodb-atlas");
const plants = mongo.db("example").collection("plants");
// Use plants.findOne to query the database
const data = await plants.findOne({ name: "daffodil" });
// You must parse data as JSON to use it as a prop
const json = JSON.parse(JSON.stringify(data));
return {
props: {
plant: json,
},
};
}
export default function Static({ plant }) {
return (
<div>
<h1>Data from Static Rendering</h1>
<div>
<div>
<p>{plant.name}</p>
<p>{plant.color}</p>
</div>
</div>
</div>
);
}

In addition to the Realm Web SDK, you can query MongoDB from Next.js in several ways:

← Apollo Client (React) - Web SDK