SkillAgentSearch skills...

Magiql

🌐 💫 Simple and powerful GraphQL Client, love child of react-query ❤️ relay

Install / Use

/learn @nksaraf/Magiql

README

<p align="center"> <img src="/public/hat2.png" width="120" /><h1 align="center"><code margin="0">magiql</code></h1><p align="center"><i>A bunch of simple but magical React hooks to work with GraphQL.<br>powered by <code><a href="https://github.com/tannerlinsley/react-query">react-query</a></code>, inspired by <code><a href="https://github.com/facebook/relay">relay</a></code> and <code><a href="https://github.com/FormidableLabs/urql">urql</a></code></i></p> </p>

A set of React hooks to work with GraphQL data. magiql stands on the shoulders of massive giants in the data-synchronization and state-management space, both conceputally and some as actual dependencies. It uses the amazing react-query library as its data-fetching and synchronization layer which forms the foundation of this library. Seriously, without react-query, this won't be any good. The API is also very similar to react-query and will be familiar to the users. It's just slightly tweaked to make it easier to work with GraphQL. On top of the these great synchronization primitives, we add normalized caching which allows us to enable the amazing developer experience that relay provides without any of the restrictions and buy-in required.

magiql is designed to be easy to adopt (moving from vanilla react-query or other GraphQL clients). Most features (like normalized caching, recoil-based store implementation, relay-compiler and build-time optimizations) are completely optional and configurable. But everything is included under one installed dependency so that you don't have to install things again and again (don't worry, the different entry-points are code-split and you will only include things that you actually use). You can start using magiql as a GraphQL Client immediately and it grows to cater to your needs as they arise by allowing extensive customization and incrementally adoption of more speciliazed features.

Features

Most of the features that we are providing are thanks to react-query. Using inspiration from relay and urql, we are able to provide a bunch of additional awesome GraphQL-specific features that you can find below

  • Auto Caching + Refetching (stale-while-revalidate, Window Refocus, Polling/Realtime)
  • Parallel + Dependent Queries
  • "Lazy" Queries
  • Request Deduplication
  • Paginated + Cursor-based Queries
  • Load-More + Infinite Scroll Queries w/ Scroll Recovery
  • Normalized caching + Entity Manipulation (multiple store implementations (recoil, react-query)
  • Fragment-first GraphQL approach (relay-style useFragment hook)
  • Request Cancellation
  • Mutations + Reactive Query Refetching
  • Optimistic Updates
  • Exchanges API to customize execution (logging, persisted queries, authentication, JWT token refresh)
  • React Suspense Support (must be enabled with React Concurrent Mode)
  • Dedicated Devtools

Using the relay-compiler (via magiql/babel or magiql cli) is required to unlock some more awesome features,

  • Schema-aware Normalized caching
  • Typescript Support + Code generation
  • Build-time GraphQL optimizations
  • Skip parsing at runtime

Note: You don't need a Relay-compliant server to get all these features in magiql. It will work with any GraphQL server. It also doesn't require you to commit to React Concurrent Mode which the new relay hooks require.

There is an example for this: https://magiql.vercel.app. You can see the components and pages folder for example code.

<img src='/public/example.gif' />

Warning: This is still in alpha stage and docs and examples are in the works

Documentation

<details> <summary><big><strong>Basic Usage</strong></big></summary>
import {
  GraphQLClientProvider,
  GraphQLClient,
  useQuery,
  graphql,
} from "magiql";

const client = new GraphQLClient({
  endpoint: "https://swapi-graphql.netlify.app/.netlify/functions/index",
});

const People = () => {
  const { data, status, error } = useQuery(
    graphql`
      query PeopleQuery($limit: Int) {
        allPeople(first: $limit) {
          edges {
            node {
              id
              name
              homeworld {
                name
              }
            }
          }
        }
      }
    `,
    {
      variables: {
        limit: 10,
      },
    }
  );

  if (status === "loading") {
    return <div>Loading...</div>;
  }

  if (error) {
    return <div>{error.message}</div>;
  }

  return (
    <div>
      {data
        ? data.allPeople?.edges?.map((edge) => (
            <div key={edge.node.id}>
              <b>{edge.node.name}</b> ({edge.node.homeworld?.name})
            </div>
          ))
        : null}
    </div>
  );
};

const App = () => {
  return (
    <GraphQLClientProvider client={client}>
      <People />
    </GraphQLClientProvider>
  );
};
</details> <details> <summary><big><strong>Installation</strong></big></summary>

To install magiql with all its features to your project, run the following commands based on if you use yarn or npm. The single dependency includes multiple entry points to code-split features and not require user to install more dependencies.

yarn add magiql graphql

# or
npm install magiql graphql --save
</details> <details> <summary><big><strong>Using the Relay compiler</strong></big></summary>

This is required to use fragments and normalized caching

To use the relay-compiler, add magiql/babel to your Babel config as a plugin, eg. in babel.config.js. The magiql Babel plugin is just a wrapper around babel-plugin-relay to include everything in one dependency. It also runs the relay-compiler in watch mode by default.

module.exports {
  presets: [ ... ],
  plugins: ["magiql/babel", ... ]
}

Or, you can run the compiler from cli using the magiql command (use magiql --watch for watch mode, recommended for development). This is also just a wrapper around the relay-compiler. You still need to add the Babel plugin, but can disable running the compiler with Babel, but setting runWithBabel to false in magiql.config.js.

magiql.config.js

If need to customize the Relay compiler away from the defaults (specified below), add a magiql.config.js file in the root directory. It is very similar to relay.config.js, but tailored a little for magiql.

module.exports = {
  schema: "./schema.graphql",
  src: "./",
  artifactDirectory: "generated",
  extensions: ["ts", "tsx", "js", "jsx", "graphql"],
  quiet: false,
  watch: boolean,
  runWithBabel: true,
  language: "typescript",
  include: ["**"],
  exclude: [
      "**/node_modules/**",
      "**/__mocks__/**",
      `**/generated/**`,
    ];
 }

</details> <details> <summary><big><strong>Working with fragments</strong></big></summary>

With GraphQL, the biggest game changer when used with React are fragments. The useFragment hook introduced by relay makes it delightful to declare the data needs of your components. These are some of the advantages:

  • Date requirements completely localized and encapsulated in your component
  • Declarative, modular and composable
  • Fragments can include nest more fragments and fits naturally with the React component model
  • Don't need to add everything to the top level query
  • Easy to ensure type safety (using relay-compiler generated files)
  • Data available independent of how the data is fetched by some parent component
  • Components only subscribe to the precise part of the data store that it cares about (down to the field level).

Usage (with fragments)

// Person.tsx
import React from "react";
import { useFragment, graphql } from "magiql";
import { Person_person } from "generated/Person_person.graphql";

export function Person({ person }: { person: Person_person }) {
  const data = useFragment(
    graphql`
      fragment Person_person on Person {
        name
        homeworld {
          name
        }
      }
    `,
    person
  );

  return (
    <div>
      <b>{data.name}</b> ({data.homeworld?.name})
    </div>
  );
}
// People.tsx
import React from "react";
import { useQuery, graphql } from "magiql";
import { PeopleQuery } from "generated/PeopleQuery.graphql";
import { Person } from "./Person";

export const People = () => {
  const { data, status, error } = useQuery<PeopleQuery>(
    graphql`
      query PeopleQuery($limit: Int) {
        allPeople(first: $limit) {
          edges {
            node {
              id
              ...Person_person
            }
          }
        }
      }
    `,
    {
      variables: {
        limit: 10,
      },
    }
  );

  return (
    <div>
      {data
        ? data.allPeople?.edges?.map((edge) => <Person person={edge.node} />)
        : null}
    </div>
  );
};
import { GraphQLClientProvider, GraphQLClient } from "magiql";
import { createRecoilStore } from "magiql/recoil-store";
import { People } from "./People";

const client = new GraphQLClient({
  endpoint: "https://swapi-graphql.netlify.app/.netlify/functions/index",
  useStore: createRecoilStore(),
});

const App = () => {
  return (
    <GraphQLClientProvider client={client}>
      <People />
    </GraphQLClientProvider>
  );
};

These features and accompanying restrictions provide an excellent authoring experience that almost seems magical when it works.

</details>

<d

View on GitHub
GitHub Stars201
CategoryDevelopment
Updated3mo ago
Forks1

Languages

TypeScript

Security Score

97/100

Audited on Nov 27, 2025

No findings