Have you ever wondered how to build a full-stack app using GraphQL instead of REST? In this tutorial, we’ll walk through how to create a simple ToDo app using React and GraphQL with Apollo.

🎯 By the end, you’ll have a working app where you can view, add, and toggle tasks — powered by a GraphQL API.

Step 1: Set Up the GraphQL Server (Backend)

mkdir graphql-server
cd graphql-server
npm init -y
npm install apollo-server graphql

Create index.js for the backend

const { ApolloServer, gql } = require('apollo-server');

const typeDefs = gql`
  type Todo {
    id: ID!
    title: String!
    completed: Boolean!
  }

  type Query {
    todos: [Todo]
  }

  type Mutation {
    addTodo(title: String!): Todo
    toggleTodo(id: ID!): Todo
  }
`;

let todos = [
  { id: "1", title: "Learn GraphQL", completed: false },
  { id: "2", title: "Build a ToDo App", completed: false },
];

const resolvers = {
  Query: {
    todos: () => todos,
  },
  Mutation: {
    addTodo: (_, { title }) => {
      const newTodo = { id: Date.now().toString(), title, completed: false };
      todos.push(newTodo);
      return newTodo;
    },
    toggleTodo: (_, { id }) => {
      const todo = todos.find(t => t.id === id);
      todo.completed = !todo.completed;
      return todo;
    },
  },
};

const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});

Step 2: Set Up the React App (Frontend)

npx create-react-app graphql-todo
cd graphql-todo
npm install @apollo/client graphql

in src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';

const client = new ApolloClient({
  uri: 'http://localhost:4000',
  cache: new InMemoryCache(),
});

ReactDOM.render(
  
    
  ,
  document.getElementById('root')
);

in src/App.js

import React, { useState } from 'react';
import { useQuery, useMutation, gql } from '@apollo/client';

const GET_TODOS = gql`
  query {
    todos {
      id
      title
      completed
    }
  }
`;

const ADD_TODO = gql`
  mutation($title: String!) {
    addTodo(title: $title) {
      id
      title
      completed
    }
  }
`;

const TOGGLE_TODO = gql`
  mutation($id: ID!) {
    toggleTodo(id: $id) {
      id
      completed
    }
  }
`;

function App() {
  const { data, loading } = useQuery(GET_TODOS);
  const [addTodo] = useMutation(ADD_TODO, {
    refetchQueries: [{ query: GET_TODOS }],
  });
  const [toggleTodo] = useMutation(TOGGLE_TODO);
  const [input, setInput] = useState('');

  if (loading) return Loading...;

  const handleAdd = () => {
    if (input.trim()) {
      addTodo({ variables: { title: input } });
      setInput('');
    }
  };

  return (
    
      📝 GraphQL ToDo List
       setInput(e.target.value)} placeholder="New task" />
      Add
      
        {data.todos.map(todo => (
           toggleTodo({ variables: { id: todo.id } })}>
            
              {todo.title}
            
          
        ))}
      
    
  );
}

export default App;

Step 3 : Start the app
in backend

node index.js

in frontend

npm start

🚀 You Did It!
You now have a working React app powered by GraphQL. You can:

  1. View todos
  2. Add a new task
  3. Toggle them done/undone

What's Next?

  • Add delete functionality
  • Store data in MongoDB or PostgreSQL
  • Deploy to Vercel or Netlify