Building a GraphQL Server with Apollo Server, Prisma, and TypeScript
Apollo Server handles GraphQL. Prisma handles the database. TypeScript ties them together with type safety. This stack gives you a fully typed pipeline fr...
12 Apr 2024

Apollo Server handles GraphQL. Prisma handles the database. TypeScript ties them together with type safety. This stack gives you a fully typed pipeline from database schema to API response.
Here's how to set it up from scratch.
Project setup
mkdir apollo-prisma-server
cd apollo-prisma-server
npm init -y
npm install apollo-server graphql prisma @prisma/client typescript ts-node @types/node
Initialize TypeScript:
npx tsc --init
Define your data model
Prisma uses a schema file to define your database structure. Create schema.prisma:
model User {
id Int @id @default(autoincrement())
name String
email String @unique
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String
author User @relation(fields: [authorId], references: [id])
authorId Int
}
Generate the Prisma client:
npx prisma generate
This creates a type-safe database client. Every query is autocompleted and type-checked by TypeScript.
Wire up Apollo Server
Create index.ts:
import { ApolloServer, gql } from 'apollo-server';
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
const typeDefs = gql`
type User {
id: Int!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: Int!
title: String!
content: String!
author: User!
}
type Query {
users: [User!]!
user(id: Int!): User
}
`;
const resolvers = {
Query: {
users: () => prisma.user.findMany({ include: { posts: true } }),
user: (_: any, { id }: { id: number }) =>
prisma.user.findUnique({ where: { id }, include: { posts: true } }),
},
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});
The trade-off
This stack gives you end-to-end type safety. Prisma generates types from your database schema. Apollo Server validates queries against your GraphQL schema. TypeScript catches mismatches at compile time.
The cost: three layers of schema. You maintain a Prisma schema, a GraphQL schema, and TypeScript types. They overlap but don't auto-sync. Tools like typegraphql-prisma or code generators can reduce the duplication, but they add their own complexity.
For small projects, this stack can feel like overkill. For production APIs with multiple clients, it pays for itself in fewer runtime bugs and faster refactoring.
Production-Ready Systems with LLMs and Agents
A live Maven cohort, 5 October to 2 November: eight 90-minute sessions where you build LLM and agent systems that survive real traffic, real cost and real failure. Tuesdays and Thursdays, 7:30 to 9:00pm London.
Cohort 2 starts 5 October. Eight live sessions, $1,500.
View the live cohortKeep reading
- TypeScript Anti-Patterns That Cost You Twice: Build Time, Runtime, and the Interview
- The Frontend Toolchain Is Now Written in Rust and Go. What That Means for You
- oxlint vs ESLint: Why I Replaced ESLint with oxlint
- SystemJS Is Dead. Native ESM Finally Won.
- Replace Axios with a Simple Custom Fetch Wrapper (Production-Ready Guide)
- Stop Shipping ChatGPT Wrappers. Ship an Agent in TypeScript, or Don't Bother.