Build a Next App with a full GraphQL API from just a JSON or CSV file


In this guide, we'll be using a JSON or CSV file with some data in it to build a fully featured GraphQL API inside a NextJS application.

For this to work, we'll need some tools, here are links to all the tools used in this guide if you'd like to check any of them out or potentially explore replacements:

Create a MongoDB database and add your data (skip if you already have a MongoDB database with data in it)

Head to and sign up for a free Atlas account or set up mongodb locally

Create your project


Create a cluster, select SHARED for the free tier.


Create your user and add your IP address to the list of allowed IP addresses (or to allow any connection).


Press connect on your cluster on


Click on Compass


Download Compass if you don't have it, and copy the connection string


Paste the connection string into Compass, replacing with the password for the database user you created earlier and press connect

Click databases


Click create


In the database name and collection name fields, describe the data type your database will contain, for example a database of football players could be called football_players or players


Once the database is created, click on it


Click the collection


You can now upload your JSON or CSV file to the database to fill it


We now have a database with the data we need, you can close Compass.

Create a NextJS app with TypeScript

Answer the questions as you like but when asked

'if you want to use the new /app directory' no

'if you want to use src directory' no

yarn create next-app --typescript

Install dependencies

yarn add prisma typegraphql-prisma -D

yarn add @apollo/server @as-integrations/next @prisma/client graphql class-validator type-graphql@next reflect-metadata graphql-scalars graphql-fields @types/graphql-fields tslib

Initialize prisma

yarn prisma init --datasource-provider mongodb

Add mongodb connection and the eventual graphql api url to .env


Pull the database schema into Prisma

yarn prisma db pull

Add generator to prisma

generator typegraphql {
  provider = "typegraphql-prisma"
  output   = "../prisma/generated/type-graphql"
  simpleResolvers = true

Create tsconfig.json or modify it at the NextJS root

  "compilerOptions": {
    "allowJs": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./*"]
    "sourceMap": true,
    "outDir": "dist",
    "strict": true,
    "lib": ["esnext", "esnext.asynciterable", "dom", "dom.iterable"],
    "target": "es2018",
    "module": "commonjs",
    "esModuleInterop": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "skipLibCheck": true
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]

Generate the prisma schema

yarn prisma generate

Create /pages/api/graphql.ts

import 'reflect-metadata';
import { resolvers } from 'prisma/generated/type-graphql';
import { PrismaClient } from '@prisma/client';
import { ApolloServer } from '@apollo/server';
import * as tq from 'type-graphql';
import { startServerAndCreateNextHandler } from '@as-integrations/next';

const prisma = new PrismaClient();

const schema = tq.buildSchemaSync({
  validate: false,

const server = new ApolloServer({ schema });

export default startServerAndCreateNextHandler(server, {
  context: async () => ({ prisma }),

Add this line to the top of _app.tsx

import 'reflect-metadata';

Start your Next app

yarn dev

Access the server at http://localhost:3000/api/graphql

Enabling CORS to use outside Vercel

Add the following to next.config.js.

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  async headers() {
    return [
        source: '/api/:path*',
        headers: [
          { key: 'Access-Control-Allow-Credentials', value: 'true' },
          { key: 'Access-Control-Allow-Origin', value: '*' },
            key: 'Access-Control-Allow-Methods',
            key: 'Access-Control-Allow-Headers',
              'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version',

module.exports = nextConfig;

Automatically generate types for the client

Install graphql-code-generator

yarn add -D ts-node @graphql-codegen/cli @graphql-codegen/client-preset

Create codegen.ts

import { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  schema: "http://localhost:3000/api/graphql",
  documents: ['pages/**/*.tsx'],
  ignoreNoDocuments: true, // for better experience with the watcher
  generates: {
    './gql/': {
      preset: 'client',
      plugins: [],

export default config;

Install concurrently

yarn add -D concurrently

Modify your dev script in package.json

"dev": "concurrently \"yarn next dev\" \"yarn graphql-codegen --watch\"",

Communicating with the API within Next

Add graphql-request and react-query

yarn add graphql-request react-query

Add React query provider and a global graphql-request client to _app.tsx

import 'reflect-metadata';
import type { AppProps } from 'next/app';
import { QueryClient, QueryClientProvider } from 'react-query';
import { GraphQLClient } from 'graphql-request';

const queryClient = new QueryClient();

export const client = new GraphQLClient(process.env.NEXT_PUBLIC_API_URL as string, {
  headers: {},

export default function App({ Component, pageProps }: AppProps) {
  return (
    <QueryClientProvider client={queryClient}>
      <Component {...pageProps} />

You're now ready to use react-query with your types, here's an example index.tsx with a database of players

import Head from 'next/head';
import { graphql } from 'gql';
import { useQuery } from 'react-query';
import React from 'react';
import { client } from './_app';

const findManyPlayers = graphql(`
  query FindManyPlayers($take: Int) {
    findManyPlayers(take: $take) {

export default function Home() {
  const { data } = useQuery(['players'], async () =>
    client.request(findManyPlayers, {
      take: 5,
  if (!data) return <></>;
  return (
        <title>Create Next App</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' />
          { => (
            <React.Fragment key={}>