GraphQL over WebSocket Protocol Client & Server

6.0.8 · active · verified Tue Apr 21

graphql-ws is a JavaScript/TypeScript library that provides a coherent, zero-dependency, and lazy implementation of the GraphQL over WebSocket Protocol for both server and client applications. The current stable version is 6.0.8, with a development cadence that includes frequent patch releases for bug fixes and minor enhancements. Major versions, like v6, typically introduce targeted breaking changes related to API adjustments or adapter integrations. A crucial differentiator is its strict adherence to the modern GraphQL over WebSocket Protocol, which makes it explicitly incompatible with the older, deprecated `subscriptions-transport-ws` library and its distinct protocol. The library offers flexible integration with various Node.js WebSocket server implementations such as `ws`, Fastify's `@fastify/websocket`, and `crossws`, catering to diverse server environments.

Common errors

Warnings

Install

Imports

Quickstart

Demonstrates setting up a basic GraphQL server with subscriptions using `ws` and `graphql-ws`, along with a client that connects and subscribes to a real-time greeting stream. Requires `ws`, `graphql-subscriptions`, `@graphql-tools/schema`, and `graphql` as peer dependencies.

import { createServer } from 'http';
import { WebSocketServer } from 'ws';
import { useServer } from 'graphql-ws/lib/use/ws';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { PubSub } from 'graphql-subscriptions';
import { createClient } from 'graphql-ws';

// --- Server Setup ---
const pubsub = new PubSub();
const HELLO_EVENT = 'hello_event';

const typeDefs = `
  type Query {
    hello: String
  }
  type Subscription {
    greetings: String
  }
`;

const resolvers = {
  Query: {
    hello: () => 'world',
  },
  Subscription: {
    greetings: {
      subscribe: () => pubsub.asyncIterator(HELLO_EVENT),
      resolve: (payload) => payload.greetings,
    },
  },
};

const schema = makeExecutableSchema({ typeDefs, resolvers });

const server = createServer((req, res) => {
  res.writeHead(404);
  res.end();
});

const wsServer = new WebSocketServer({
  server,
  path: '/graphql',
});

useServer(
  {
    schema,
    context: async (ctx) => {
      // Example: access the websocket instance through ctx.extra.socket in v6+
      // const socket = ctx.extra.socket;
      return { currentUser: 'someUser' };
    }
  },
  wsServer
);

server.listen(4000, () => {
  console.log('GraphQL server running on http://localhost:4000/graphql');
  console.log('WebSocket server running on ws://localhost:4000/graphql');

  let count = 0;
  setInterval(() => {
    pubsub.publish(HELLO_EVENT, { greetings: `Hello from server! (${count++})` });
  }, 2000);
});

// --- Client Setup ---
const client = createClient({
  url: 'ws://localhost:4000/graphql',
  webSocketImpl: WebSocket, // Required for Node.js environments; in browser, it's global
  on: {
    connected: () => console.log('Client connected to server.'),
    closed: (event) => console.log(`Client disconnected: ${event.code} - ${event.reason}`),
    error: (err) => console.error('Client error:', err),
  },
});

async function subscribeToGreetings() {
  const onNext = ({ data }) => {
    console.log('Received greeting:', data.greetings);
  };

  const onError = (err) => {
    console.error('Subscription error:', err);
  };

  const onComplete = () => {
    console.log('Subscription complete.');
  };

  const unsubscribe = client.subscribe(
    {
      query: `subscription { greetings }`,
    },
    {
      next: onNext,
      error: onError,
      complete: onComplete,
    }
  );

  setTimeout(() => {
    unsubscribe();
    console.log('Unsubscribed from greetings.');
    client.dispose(); // Close the WebSocket connection
    server.close(); // Close the HTTP/WebSocket server
  }, 10000);
}

// Run 'npm install ws graphql-subscriptions @graphql-tools/schema graphql' first
subscribeToGreetings().catch(console.error);

view raw JSON →