Step 1 • Before You Start
Prerequisites — REST APIs, Node.js, and TypeScript beginner GraphQL is an API query language that runs over HTTP — you need to understand what APIs are before designing better ones. Be comfortable with REST API concepts (endpoints, HTTP methods, status codes, JSON), Node.js (async/await, modules, npm), and TypeScript basics (types, interfaces, generics). You should also understand basic database concepts (relational vs document) since GraphQL is typically a layer over a data source. Knowing what's painful about REST will make GraphQL's benefits click.
Backend Node.js 5h Step 2 • Foundations
GraphQL Concepts — Why GraphQL Exists beginner GraphQL was created by Facebook in 2012 to solve real problems: over-fetching (getting fields you don't need), under-fetching (needing multiple round-trips), and rigid versioning. Understand the core concepts: a single endpoint (/graphql), the client specifies exactly what data it needs in the query, the server responds with exactly that shape, strongly-typed schema as a contract between client and server. Learn the three operation types: query (read), mutation (write), subscription (real-time). GraphQL is transport-agnostic but almost always uses HTTP.
Backend GraphQL 3h Step 3 • Foundations
The Type System and Schema Definition Language beginner GraphQL is strongly typed. Learn the Schema Definition Language (SDL): scalar types (String, Int, Float, Boolean, ID), Object types (type User { id: ID!, name: String! }), non-null (!) vs nullable, List types ([User!]!), Enum types, Input types (for mutation arguments), Interface types (shared fields across types), Union types (one of many types), and the root types (type Query, type Mutation, type Subscription). The schema is the contract — clients can introspect it to discover available operations.
Backend GraphQL 5h Step 4 • Foundations
Queries, Mutations, and Variables beginner Learn the GraphQL query language as a client. Queries: select specific fields, nest related objects (author { name }), use aliases (featuredPost: post(id: 1)), fragments for reusable field sets. Mutations: write operations that return the modified object — always return something useful. Variables: pass dynamic values via $variable: Type syntax instead of string interpolation (never interpolate — it's a security risk). Operation names help with debugging and logging. Directives: @include(if: $bool) and @skip(if: $bool) for conditional fields.
Backend GraphQL 5h Step 5 • intermediate
Fragments & Directives intermediate Reuse field selections with named fragments and inline fragments (for union/interface types). Apply built-in directives: @skip(if: Boolean) and @include(if: Boolean) for conditional fields, @deprecated(reason:) for schema evolution. Create custom schema directives to implement cross-cutting concerns like @auth, @rateLimit, or @formatDate using graphql-tools mapSchema.
Backend GraphQL 4h Step 6 • Server
Apollo Server — Building Your First GraphQL API beginner Apollo Server is the most popular GraphQL server for Node.js. Set up Apollo Server 4 (standalone with @as-integrations/express for production). Define your schema with typeDefs (SDL string), implement resolvers (an object matching the schema shape), and wire them together. Use Apollo Sandbox (localhost:4000) for interactive querying. Understand the resolver function signature — (parent, args, context, info) — where context holds per-request data (auth, dataloaders, db connections). Learn how GraphQL Yoga is a lighter alternative.
Backend GraphQL 6h Step 7 • Server
Resolvers — Data Fetching and Context intermediate Resolvers are functions that return data for a field. Understand the default resolver (returns the property from the parent object), field-level resolvers for computed fields, nested resolvers and the parent argument (resolver chaining), and resolver return types (objects, promises, arrays). Context is created once per request and passed to every resolver — use it for authentication (decode JWT → user), database connections (Prisma client, pg pool), and DataLoaders. Never put mutable state in context.
Backend GraphQL 6h Step 8 • Server
Connecting to a Database with Prisma intermediate GraphQL resolvers need a data source. Prisma is the most popular ORM for GraphQL APIs — type-safe queries generated from a schema.prisma file. Learn Prisma Client (CRUD methods, filtering, pagination, relations), Prisma Migrate for schema migrations, and how to put the Prisma client in context so all resolvers share one connection. Alternatively, use Drizzle ORM (lightweight, SQL-focused) or raw SQL with postgres.js. Understand the N+1 problem when resolving related objects — you'll solve it with DataLoader.
Backend GraphQL 7h Step 9 • Performance
DataLoader — Solving the N+1 Problem intermediate The N+1 problem is GraphQL's most common performance pitfall: if you resolve a list of 100 Posts and each Post resolver fetches its Author separately, you make 101 database queries. DataLoader solves this with batching — it collects all requested IDs within a single event loop tick and makes one batch query (SELECT * FROM users WHERE id IN (...)). Caching — DataLoader caches results per-request so the same ID is never fetched twice. Create DataLoaders in context (one per request) for Users, Comments, etc.
Backend GraphQL 5h Step 10 • Server
Error Handling and Custom Errors intermediate GraphQL has a unique error model — partial success is valid. A response can have both data and errors. Understand GraphQL error types: unexpected errors (500-like, should be masked in production), user-visible errors (authentication, validation, not-found). Use GraphQLError with extensions for structured errors ({ code: 'UNAUTHENTICATED', message: '...' }). Apollo Server 4 uses formatError to sanitize errors before sending to clients. Learn the Union error pattern — return a union type (CreatePostSuccess | CreatePostError) instead of throwing, for type-safe error handling.
Backend GraphQL 4h Step 11 • Design
Schema Design Best Practices intermediate Great schema design makes APIs a joy to use. Follow these principles: design for the client, not the database (expose what clients need, not table rows), use nullable fields for optional data (null means 'not present'), use non-null for fields that are always present, design mutations with dedicated input types (CreatePostInput) and rich return types, prefer connections for paginated lists (Relay-style cursor pagination: edges/node/pageInfo), use enums for finite sets, version implicitly (add fields, never remove — use @deprecated), and name things consistently.
Backend GraphQL 5h Step 12 • intermediate
Pagination — Cursor-Based & Relay Spec intermediate Implement offset-based pagination (simple but unstable with inserts) and cursor-based pagination (opaque cursors, stable ordering). Follow the Relay Cursor Connections Specification: Connection type, Edge type, PageInfo with hasNextPage / hasPreviousPage / startCursor / endCursor. Implement both directions (forward: first/after, backward: last/before).
Backend GraphQL 5h Step 13 • Real-Time
Real-Time with Subscriptions and WebSockets intermediate GraphQL subscriptions push data to clients over a persistent connection (WebSockets or SSE). The server publishes events to a PubSub system (in-memory PubSub for dev, Redis PubSub for production scale), and the subscription resolver subscribes to relevant events. Use graphql-ws (WebSocket subprotocol) with Apollo Server or GraphQL Yoga. Learn how to filter subscription events with withFilter(), authenticate WebSocket connections, and handle subscription cleanup. Use server-sent events (SSE) for simpler one-directional streams.
Backend GraphQL 6h Step 14 • Client
Apollo Client — GraphQL on the Frontend intermediate Apollo Client is the most popular GraphQL client. Set up ApolloProvider with an ApolloClient instance (InMemoryCache, httpLink, authLink for tokens). Learn useQuery (loading/error/data, refetch, polling), useMutation (execute function, optimistic updates, refetchQueries), useLazyQuery (trigger on demand). The InMemoryCache normalizes data by type + id — understand cache reads/writes for optimistic UI. Use the Apollo DevTools browser extension to inspect cache state and network operations.
Frontend GraphQL 7h Step 15 • Client
GraphQL Code Generator — Type Safety End-to-End intermediate GraphQL Code Generator introspects your schema and operations to generate TypeScript types — no manual typing. Configure @graphql-codegen/cli with the typescript, typescript-operations, and typescript-react-apollo plugins. Write your queries and mutations in .graphql files, run codegen, and get typed hooks (useGetPostsQuery, useCreatePostMutation). This gives full type safety from schema to component. Set up codegen to run on schema changes in CI. Use graphql-tag (gql) template literal for inline documents.
Frontend TypeScript 5h Step 16 • Performance
Performance — Caching, Complexity, and Pagination advanced Production GraphQL needs performance guardrails. Query complexity analysis — assign cost to fields, reject queries above a threshold (graphql-query-complexity). Depth limiting — reject deeply nested queries. Response caching — cache at the HTTP layer (persisted queries + GET requests), field-level caching with @cacheControl directives, CDN-friendly responses. Persisted queries — send a hash instead of the full query to reduce request size and enable CDN caching. Defer and stream (@defer, @stream) directives for streaming large responses. Apollo Server performance plugins.
Backend GraphQL 6h Step 17 • Testing
Testing GraphQL APIs intermediate Test GraphQL APIs at multiple levels. Unit test resolvers (pure functions — mock context, assert return values). Integration test the full server with executeOperation() (Apollo Server's in-process test executor — no HTTP overhead). End-to-end test with a real HTTP client (supertest or fetch) and a test database. Use jest-mock for mocking Prisma. MSW (Mock Service Worker) for frontend — intercept GraphQL requests and return mock responses. Test subscription behavior with AsyncIterator mocks.
Backend GraphQL 6h Step 18 • Advanced
Schema Federation and Microservices advanced Apollo Federation allows multiple GraphQL services (subgraphs) to compose into a single supergraph. Each service owns its slice of the schema — the Users service owns User, the Products service owns Product, the Orders service owns Order. The Apollo Router (or Gateway) merges them and routes queries. Learn entity types (@key directive), entity references (@external), and how the gateway resolves cross-service queries. Schema composition is validated with the Rover CLI and Apollo Studio. Use Federation when you have multiple teams owning different domains.
Backend GraphQL 8h Step 19 • Production
Production — Security, Monitoring, and Deployment advanced Ship GraphQL with confidence. Security: disable introspection in production (reveals your schema to attackers), validate query depth and complexity, use persisted queries to allow only known operations, sanitize error messages. Monitoring: track resolver timing with Apollo Studio traces, integrate OpenTelemetry for distributed tracing, log slow queries and errors to Sentry. Rate limiting at the operation level. Use Apollo Studio Schema Checks in CI to prevent breaking changes. Deploy with zero-downtime rolling updates — GraphQL servers are stateless and trivially horizontally scalable.
Backend GraphQL 6h