Full Stack (MERN) + GraphQL Boilerplate / Starter Part-II
Next.js + React + GraphQL + Express + Apollo + MongoDB + TypeScript
Author

Date

Book a call
This is the second article of the Full Stack (MERN) + GraphQL Boilerplate / Starter series:
Note: Before proceeding with this article, you need to set up the server for the boilerplate first, which is mentioned in the first part of the series. Follow the link above to read it.
Repository Link: - https://github.com/garganurag893/Next.js_GraphQL_Express_Apollo_Boilerplate
Next.js
Building a server-side rendered React website is hard. Next.js commits to solving this problem beautifully.
It comes with some handy features:
So, Let’s start by creating a new app :
Folder structure
Make the following folder structure to house everything:
Adding Dependencies:
Now we will add all GraphQL dependencies required for next.js :
yarn add @apollo/react-hooks apollo-cache-inmemory apollo-client apollo-link-http apollo-link-ws graphql graphql-tag subscriptions-transport-ws isomorphic-unfetch next-with-apolloAdding TypeScript:
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
The presence of a tsconfig.json file in a directory indicates that the directory is the root of a TypeScript project. The tsconfig.json file specifies the root files and the compiler options required to compile the project. A project is compiled in one of the following ways:
Using tsconfig :
tsconfig.json☟
{
"compilerOptions": {
"target": "es6",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve"
},
"exclude": [
"node_modules"
],
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx"
]
}To connect the Apollo server to the client, all we need is your hosted server URL and a web socket link, which in my case is:
src/config/index.ts☟
/**
* Configuration
*/
export const SERVER = 'http://localhost:4020/graphql';
export const WEB_SOCKET_LINK = 'ws://localhost:4020/graphql';Now it's time to finally start some coding. Navigate to the src folder and create a file configureClient.js where we will write all the configuration required to configure GraphQl Client.
src/configureClient.ts ☟
/**
* Apollo Client Configuration
*/
import { ApolloClient } from 'apollo-client';
import { split, ApolloLink, concat } from 'apollo-link';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { getMainDefinition } from 'apollo-utilities';
import withApollo from 'next-with-apollo';
import { HttpLink } from 'apollo-link-http';
import fetch from 'isomorphic-unfetch';
import { WebSocketLink } from 'apollo-link-ws';
import Cookies from 'js-cookie';
import { SERVER, WEB_SOCKET_LINK } from './config';
interface Definintion {
kind: string;
operation?: string;
}
let authToken = null;
const httpLink = new HttpLink({
fetch,
uri: SERVER,
});
const authMiddleware = new ApolloLink((operation, forward) => {
operation.setContext({
headers: {
authorization: authToken || null,
},
});
// Add onto payload for WebSocket authentication
(operation as any & { authToken: string | undefined }).authToken = authToken;
return forward(operation);
});
const webSocketLink: any = process.browser
? new WebSocketLink({
uri: WEB_SOCKET_LINK,
options: {
reconnect: true,
},
})
: null;
/**
* Set Token
* @param token
*/
export const setToken = async (token: string) => {
try {
authToken = token ? `Bearer ${token}` : null;
Cookies.set('token', authToken, { expires: 7 });
} catch (error) {
console.log(error);
}
};
/**
* Set Token In Request
* @param token
*/
export const setTokenInRequest = async (token: string) => {
try {
authToken = token ? token : null;
return authToken;
} catch (error) {
console.log(error);
}
};
/**
* Destroy Token
* For logout purpose
*/
export const destroyToken = async () => {
try {
Cookies.remove('token');
authToken = null;
} catch (error) {
console.log(error);
}
};
const link = process.browser
? split(
({ query }) => {
const { kind, operation }: Definintion = getMainDefinition(query);
return kind === 'OperationDefinition' && operation === 'subscription';
},
webSocketLink,
httpLink
)
: httpLink;
export default withApollo(
({ initialState }) =>
new ApolloClient({
link: concat(authMiddleware, link),
cache: new InMemoryCache().restore(initialState || {}),
})
);Now to add this configuration to your Next.js app navigate to the pages folder of your project directory and create a file with name _app.tsx
Note: Filename should be perfectly the same as _app.tsx, nothing else.
_app.tsx ☟
/**
* App Configuration
*/
import React from 'react';
import App from 'next/app';
import { ApolloProvider } from '@apollo/react-hooks';
import withData from '../src/configureClient';
class MyApp extends App<any> {
render() {
const { Component, pageProps, apollo } = this.props;
return (
<ApolloProvider client={apollo}>
<Component {...pageProps} />
</ApolloProvider>
);
}
}
// Wraps all components in the tree with the data provider
export default withData(MyApp);That’s it. GraphQL Apollo Client Setup is complete….?
React makes it painless to create interactive UIs. Design simple views for each state in your application and React will efficiently update and render just the right components when your data changes. We will make a Next.js app with basic auth functionality using GraphQL.
So, Let’s start by creating a new app:
Folder Structure
Make the following folder structure to house everything:
Adding Dependencies
Now we will add all GraphQL dependencies required for react.js :
To connect the apollo server to the client all we need is your hosted server URL and a web socket link, which in my case is:
src/config/index.ts☟
/**
* Configuration
*/
export const SERVER = 'http://localhost:4020/graphql';
export const WEB_SOCKET_LINK = 'ws://localhost:4020/graphql';
Now it's time to finally start some coding. Navigate to the src folder and create a file configureClient.js where we will write all the configuration required to configure GraphQL Client
src/configureClient.ts ☟
/**
* Apollo Client Configuration
*/
import { ApolloClient } from 'apollo-client';
import { split, ApolloLink, concat } from 'apollo-link';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { getMainDefinition } from 'apollo-utilities';
import { HttpLink } from 'apollo-link-http';
import fetch from 'isomorphic-unfetch';
import { WebSocketLink } from 'apollo-link-ws';
import Cookies from 'js-cookie';
import { SERVER, WEB_SOCKET_LINK } from './config';
interface Definintion {
kind: string;
operation?: string;
}
let authToken = '';
const httpLink = new HttpLink({
fetch,
uri: SERVER,
});
const authMiddleware = new ApolloLink((operation, forward) => {
operation.setContext({
headers: {
authorization: authToken || null,
},
});
// Add onto payload for WebSocket authentication
(operation as any & { authToken: string | undefined }).authToken = authToken;
return forward(operation);
});
const webSocketLink: WebSocketLink = new WebSocketLink({
uri: WEB_SOCKET_LINK,
options: {
reconnect: true,
},
});
/**
* Set Token
* @param token
*/
export const setToken = async (token: string | undefined) => {
try {
authToken = token ? `Bearer ${token}` : '';
Cookies.set('token', authToken, { expires: 7 });
} catch (error) {
console.log(error);
}
};
/**
* Get Token & Set Token In Request
*/
export const getToken = async () => {
try {
const token = Cookies.get('token');
authToken = token ? token : '';
return authToken;
} catch (error) {
console.log(error);
}
};
/**
* Destroy Token
* For logout purpose
*/
export const destroyToken = async () => {
try {
Cookies.remove('token');
authToken = '';
} catch (error) {
console.log(error);
}
};
const link = split(
({ query }) => {
const { kind, operation }: Definintion = getMainDefinition(query);
return kind === 'OperationDefinition' && operation === 'subscription';
},
webSocketLink,
httpLink
);
const client = new ApolloClient({
link: concat(authMiddleware, link),
cache: new InMemoryCache().restore({}),
connectToDevTools: true,
});
export default client;
Now to add this configuration to your react.js app navigate to the src folder of your project directory and edit App.tsx
src/App.tsx ☟
/**
* App Component
*/
import React from 'react';
import { ApolloProvider } from '@apollo/react-hooks';
import apolloClient from './configureClient';
import Welcome from './screens/Welcome';
const App = () => {
return (
<ApolloProvider client={apolloClient}>
<Welcome />
</ApolloProvider>
);
};
export default App;
That’s it GraphQL Apollo Client Setup is complete.?
Conclusion
The main advantage of using this boilerplate is that every line of code is written in TypeScript. This is a programming language that’s used everywhere, both for client-side code and server-side code. With one language across tiers, there’s no need for context switching.
For tech stack with multiple programming languages, developers have to figure out how to interface them together. With the TypeScript stack, developers only need to be proficient in TypeScript and JSON.
Overall, using the MERN stack enables developers to build highly efficient web applications.
Book a Discovery Call
Related Articles.
More from the engineering frontline.
Dive deep into our research and insights on design, development, and the impact of various trends to businesses.

Apr 9, 2026
From RFPs to Revenue: How We Built an AI Agent Team That Writes Technical Proposals in 60 Seconds
GeekyAnts built DealRoom.ai — four AI agents that turn RFPs into accurate technical proposals in 60 seconds, with real-time cost breakdowns and scope maps.

Apr 6, 2026
How We Built an AI System That Automates Senior Solution Architect Workflows
Discover how we built a 4-agent AI co-pilot that converts complex RFPs into draft technical proposals in 15 minutes — with built-in conflict detection, assumption surfacing, and confidence scoring.

Apr 6, 2026
AI Code Healer for Fixing Broken CI/CD Builds Fast
A deep dive into how GeekyAnts built an AI-powered Code Healer that analyzes CI/CD failures, summarizes logs, and generates code-level fixes to keep development moving.

Apr 2, 2026
A Real-Time AI Fraud Decision Engine Under 50ms
A deep dive into how GeekyAnts built a real-time AI fraud detection system that evaluates transactions in milliseconds using a hybrid multi-agent approach.

Apr 1, 2026
Building an Autonomous Multi-Agent Fraud Detection System in Under 200ms
GeekyAnts built a 5-agent fraud detection pipeline that makes decisions in under 200ms — 15x cheaper than single-model systems, with full explainability built in.

Mar 31, 2026
Building a Self-Healing CI/CD System with an AI Agent
When code breaks a pipeline, developers have to stop working and figure out why. This blog shows how an AI agent reads the error, finds the fix, and submits it for review all on its own.