GraphQL is an API query language that allows clients to get the data they need more efficiently and flexibly than traditional REST APIs. In recent years, GraphQL has gained a lot of popularity and has become one of the most popular technologies for API creation. At the same time, Next.js is a highly efficient and scalable web application development framework that has become very popular with web developers. This tutorial will explore how to create a GraphQL server and client with Next.js to provide a more efficient and flexible development experience for our users. this tutorial assumes you have basic knowledge of GraphQL and Nextjs (pages directory). Before starting: We will use to make requests and retrieve fake JSON data, in particular, we will use dummyJSON https://dummyjson.com/docs/users Setting Up We create a new Next.js project with the following command and follow the steps indicated. This time we will use , you can use the package manager of your choice. pnpm pnpm create-next-app We install the dependencies that we will need in the project: pnpm install @apollo/server graphql @as-integrations/next apollo-server-core @apollo/client graphql-tag @nextui-org/react is the main library for Apollo Server itself. @apollo/server: An Apollo Server integration for use with Next.js. @as-integrations/next: to create and consume API’s in Graphql language. graphql: to create and manage GraphQL servers simply and flexibly. apollo-server-core: to handle GraphQL requests and statuses on clients. @apollo/client: to build and manipulate GraphQL queries in JavaScript. graphql-tag: library of user interface components. I will use this library only to quickly style the application, feel free to use the one you want. @nextui-org/react After that, we will create the following structure for the project: ... ├── src/ │ ├── graphql/ │ │ ├── queries/ │ │ │ ├── getUseres.gql │ │ │ └── searchUser.gql │ │ ├── apollo-client.js │ │ ├── resolvers.js │ │ └── schemas.js │ ├── pages/ │ │ ├── api/ │ │ │ └── graphql.js │ │ ├── _app.js │ │ ├── _document.js │ │ └── index.js │ │ ... │ ├── utils/ │ │ └── cors.js ├── .env.local ... Now we will create the file and create the environment variables that we are going to use: .env.local /* we add the prefix NEXT_PUBLIC_ to the variable that will havethe graphql server url defined, this way we will be able toaccess to it client side */ NEXT_PUBLIC_URL_SERVER_GRAPHQL=http://localhost:3000/api/graphqlURL_API=https://dummyjson.com/users Graphql server We will create the GraphQL server inside the directory since it’s where the server created by Nextjs lives. 1— /api : graphql.js import { ApolloServer } from "@apollo/server" import { startServerAndCreateNextHandler } from '@as-integrations/next' import { ApolloServerPluginLandingPageGraphQLPlayground } from "apollo-server-core" import typeDefs from "@/graphql/schemas" import resolvers from "@/graphql/resolvers" import allowCors from "@/utils/cors" const apolloServer = new ApolloServer({ typeDefs, resolvers, plugins: [ApolloServerPluginLandingPageGraphQLPlayground()] }) const handler = startServerAndCreateNextHandler(apolloServer, { context: async (req, res) => ({ req, res }), }) export default allowCors(handler) The GraphQL server has two main parts: schemas (typeDefs) and resolvers. The schemas define the structure of the data and the queries that can be made to the server, while the resolvers define how the data is obtained and processed. We also add to the initial configuration of the server the definition of . This plugin provides a GraphQL playground page that allows us to test queries in a more user-friendly way. ApolloServerPluginLandingPageGraphQLPlayground Finally, is used to enable Cross-Origin Resource Sharing (CORS) support on the server. This function adds the necessary CORS headers to the response. allowCors : utils/cors.js const allowCors = (fn) => async (req, res) => { res.setHeader('Access-Control-Allow-Credentials', true) res.setHeader('origin', 'https://nextjs-graphql-server-client.vercel.app') res.setHeader('Access-Control-Allow-Origin', req.headers.origin || '*') // another common pattern res.setHeader('Access-Control-Allow-Methods', 'GET,OPTIONS,PATCH,DELETE,POST,PUT') res.setHeader( 'Access-Control-Allow-Headers', 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version', ) if (req.method === 'OPTIONS') { res.status(200).end() return } await fn(req, res) } export default allowCors In this file, we have defined the basic headers that the app needs to be able to make requests to the Graphql server. This middleware is fully customizable to the requirements of your application, you can remove or add more headers, either known headers or custom headers that only your app uses. You need to add the necessary headers so you can make requests to the server either using this middleware or directly in your requests. Schema creation 2— : schemas.js import { gql } from 'graphql-tag' const typeDefs = gql` type Query { users: [User] searchUser(value:String):[User] } type User { id: ID firstName: String lastName: String email: String username: String image: String } ` export default typeDefs We define a GraphQL schema using . The function is used to convert a string into a valid GraphQL schema document. gql gql In the Schema, we define a query type called , which has a property called , which is a list of objects of type . Query users User We also have the query called which receives a string value with which we will filter the users that match the value. For this tutorial, we will create the type with only some of the API returned properties. searchUser User Resolvers creation 3— : resolvers.js const resolvers = { Query: { users: async () => { try { const response = await fetch(process.env.URL_API) const data = await response.json() return data.users.map(u => { return { id: u.id, firstName: u.firstName, lastName: u.lastName, email: u.email, username: u.username, image: u.image } }) } catch (error) { throw new Error("Something went wrong") } }, searchUser: async (_, { value }) => { try { const response = await fetch(`${process.env.URL_API}/search?q=${value}`) const data = await response.json() return data.users.map(u => { return { id: u.id, firstName: u.firstName, lastName: u.lastName, email: u.email, username: u.username, image: u.image } }) } catch (error) { throw new Error("Something went wrong") } } } } export default resolvers We define the resolvers that correspond to each query. The resolvers request the external API, which returns a JSON with a list of users. We do a mapping of the data received from the API to return only the data that we will use in the application. In case something goes wrong during the request or the data processing, an exception is thrown with the message “Something went wrong”. Now let’s run the application, go to the path and execute the queries created: /api/graphql GraphQL client Creation of an instance of an Apollo client. 1— import { ApolloClient, InMemoryCache } from "@apollo/client" import { ApolloClient, InMemoryCache } from "@apollo/client" const client = new ApolloClient({ uri: process.env.NEXT_PUBLIC_URL_SERVER_GRAPHQL, cache: new InMemoryCache(), }) export default client The client is created with two main properties: and . The uri property is the GraphQL API address to which the client will connect. In this case, we will use the environment variable created earlier that stores the API address. uri cache NETX_PUBLIC_URI_SERVER_GRAPHQL The property is used to store the data that is downloaded from the API in cache. This way, the client can access the data without making a new API query. cache This component provides functionality, which allows an instance of an Apollo client to access all components rendered within it. 2— ApolloPrivider import { ApolloProvider } from '@apollo/client' import client from "@/graphql/apollo-client" export default function App({ Component, pageProps }) { return ( <ApolloProvider client={client}> <Component {...pageProps} /> </ApolloProvider> ) } Creation of queries in files. 3— .gql : getUser.gql query getUsers { users { id firstName lastName email username image } } : searchUser.gql query getSearchUsers($value: String) { searchUser(value: $value) { id firstName lastName email username image } } : next.config.js const nextConfig = { ... webpack: (config, options) => { config.module.rules.push({ test: /\.(graphql|gql)/, exclude: /node_modules/, loader: "graphql-tag/loader" }) return config } ... } In order to use or files in Next.js, it’s necessary to add a webpack configuration in the Nextjs configuration. .graphql .gql Here you can read more about it. Making server-side and client-side requests. 4— : index.js import { useEffect, useRef, useState } from 'react' import { useLazyQuery, useQuery } from '@apollo/client' import Head from 'next/head' import { Button, Container, Grid, Input, Spacer, User, Row, Loading } from "@nextui-org/react" import GET_USERS from '@/graphql/queries/getUsers.gql' import SEARCH_USERS from '@/graphql/queries/searchUsers.gql' export default function Home() { const [users, setUsers] = useState([]) const [searchValue, setSearchValue] = useState('') const usersRef = useRef(null) const { data, loading, error } = useQuery(GET_USERS) const [getSearchedUsers] = useLazyQuery(SEARCH_USERS, { fetchPolicy: 'network-only', onCompleted(data) { setUsers(data.searchUser) } }) useEffect(() => { if (data) { setUsers(data.users) usersRef.current = data.users } }, [data]) const searchUser = () => { getSearchedUsers({ variables: { value: searchValue } }) } if (error) { console.error(error) return null } return ( <> <Head> <title>Nextjs and Graphql Setup</title> <meta name="description" content="Generated by create next app" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" href="/favicon.ico" /> </Head> <main > <Container css={{ display: 'flex', justifyContent: 'center' }}> <Spacer y={2.5} /> <Row justify="center" align="center"> <Input clearable labelPlaceholder="User" onClearClick={() => setUsers(usersRef.current)} initialValue={searchValue} onChange={(e) => setSearchValue(e.target.value)} /> <Button color="gradient" auto onClick={() => searchUser()}> Search user </Button> </Row> <Spacer y={2.5} /> <Row justify="center" align="center"> {loading ? <Loading /> : <Grid.Container gap={2} justify="center"> {users.map(u => ( <Grid xs={3} key={u.id} > <User src={u.image} name={`${u.firstName}${u.lastName}`} description={u.email} size="lg" bordered color="gradient" /> </Grid> )) } </Grid.Container> } </Row> </Container> </main> </> ) } In the above code, we will use the hook to get the users with the query and then save it in the state. useQuery GET_USERS We also use Apollo’s hook to perform a search on the users when the user clicks on the “Search user” button. When the query is finished we save the results in the state. useLazyQuery That’s it! now we can use graphql server-side and client-side. You can add as many queries and resolvers as you need. The app looks as follows: See the demo here Repo here Conclusion In summary, using GraphQL in a Next.js project can significantly improve the application’s efficiency, flexibility, documentation, security, and scalability. Hopefully, this will serve as a guideline for your future projects. Want to connect with the author? Love connecting with friends all around the world on . Twitter Read more: How to Create a Modern Skeleton Loader in React to Improve User Experience How to Simulate a Backend REST API with json-server for CRUD Development in React Also published . here