Generate React TypeScript hooks and models from GraphQL schemas.
Typed queries, mutations & subscriptions over the native Fetch API, with optional TanStack Query (useQuery/useMutation) hooks — generated straight from your schema (SDL).
- NPM Package: @metaengine/graphql-react
- NuGet Package: MetaEngine.TypeScript.GraphQL.React
- Website: metaengine.eu/packages/graphql-react
- ✅ React 18+ — generated API functions plus optional hooks
- ✅ TanStack Query —
useQuery/useMutationhooks with--tanstack-query - ✅ Queries, mutations & subscriptions — typed operations generated straight from SDL
- ✅ Native Fetch API — zero runtime dependencies in the generated client
- ✅ Reusable fragments — opt into named fragment spreads with
--fragments - ✅
@oneOfinputs — idiomatic tagged-union input types with--one-of-inputs - ✅ Custom scalar mapping — well-known scalars resolve to idiomatic TS types; override any with
--custom-scalar - ✅ Smart error handling & retries — HTTP-status routing and exponential-backoff retries via
ClientConfig - ✅ TypeScript — fully typed clients and models
- ✅ Tree-shakeable — separate file per model and per operation type
npm install --save-dev @metaengine/graphql-reactOr use directly with npx:
npx @metaengine/graphql-react <input> <output>- Node.js 18.0 or later
- .NET 8.0 or later runtime (Download)
- React 18+ (and
@tanstack/react-queryif you use--tanstack-query)
npx @metaengine/graphql-react schema.graphql ./src/api \
--documentation \
--tanstack-querynpx @metaengine/graphql-react schema.graphql ./src/api \
--tanstack-query \
--retries 3 \
--error-handlingAdd to your package.json:
{
"scripts": {
"generate:api": "metaengine-graphql-react schema.graphql ./src/api --tanstack-query --error-handling"
}
}Then run:
npm run generate:apiVite:
npx @metaengine/graphql-react schema.graphql ./src/api --base-url-env VITE_API_URLNext.js:
npx @metaengine/graphql-react schema.graphql ./src/api --base-url-env NEXT_PUBLIC_API_URLCreate React App:
npx @metaengine/graphql-react schema.graphql ./src/api --base-url-env REACT_APP_API_BASE_URL| Option | Description | Default |
|---|---|---|
--fragments |
Emit reusable named fragments for object-type selections | false |
--one-of-inputs |
Generate idiomatic @oneOf input types (tagged-union inputs) |
false |
--custom-scalar <Scalar=target> |
Map a GraphQL custom scalar to a TS type. Repeatable. See Custom scalar mappings | - |
--base-url-env <name> |
Environment variable name for base URL | REACT_APP_API_BASE_URL |
--tanstack-query |
Generate TanStack Query hooks (useQuery/useMutation) |
false |
--error-handling |
Smart error handling based on HTTP status semantics | false |
--retries <max-attempts> |
Enable retries with exponential backoff (status codes 429, 503) | - |
--documentation |
Generate JSDoc comments from SDL descriptions | false |
--date-transformation |
Convert Date-typed scalar fields (e.g. DateTime) in responses to Date objects |
false |
--options-threshold <n> |
Parameter count for options object | 4 |
--service-suffix <suffix> |
Service naming suffix | Api |
--types-barrel |
Emit an index.ts barrel per folder plus a root index.ts |
false |
--clean |
Clean output directory (remove files not in generation) | false |
--verbose |
Enable verbose logging | false |
--help, -h |
Show help message | - |
output/
├── models/ # One file per type (object, input, enum, union)
│ ├── user.ts # export interface User { ... }
│ ├── role.ts # export type Role = 'ADMIN' | 'MEMBER' | ...
│ ├── scalars.ts # custom scalar type aliases
│ └── ...
├── services/ # One file per root operation type
│ ├── query.api.ts # query operations (+ hooks with --tanstack-query)
│ ├── mutation.api.ts # mutation operations
│ ├── subscription.api.ts # subscription operations
│ └── fragments.ts # (with --fragments) reusable named fragments
├── client.ts # ApiClient, createClient, getDefaultClient, executeGraphQL<T>
└── errors.ts # GraphQLError / HttpError helpers
Each operation collapses to a one-line call to the shared executeGraphQL<T> helper in client.ts, which owns the POST /graphql request and the data/errors envelope handling.
npx @metaengine/graphql-react schema.graphql ./src/api --tanstack-queryGenerates useQuery/useMutation hooks in the services/*.api.ts files alongside the plain async functions. Requires @tanstack/react-query in your project.
npx @metaengine/graphql-react schema.graphql ./src/api --fragmentsEmits services/fragments.ts with one named fragment per object type. Operation selections reference fragment spreads (...UserFields) instead of repeating field sets.
npx @metaengine/graphql-react schema.graphql ./src/api --one-of-inputsRenders @oneOf input types as idiomatic TypeScript discriminated unions where exactly one member may be set. Without the flag, the input renders as a plain interface with all-optional fields.
Subscription operations are generated into services/subscription.api.ts. The generated client accepts the WebSocket endpoint at runtime via ClientConfig.graphqlWsUrl.
npx @metaengine/graphql-react schema.graphql ./src/api --error-handlingAdds an errorHandling config to ClientConfig with smart HTTP-status routing — 403 / 404 resolve to null, 400 / 409 / 422 return the error body, 401 / 500 / 502 / 503 throw.
npx @metaengine/graphql-react schema.graphql ./src/api --retries 3Adds a retry config to ClientConfig that reattempts retryable responses (429, 503) up to the given number of attempts with exponential backoff.
GraphQL custom scalars resolve to idiomatic TypeScript types. Well-known scalars are mapped out of the box; any other custom scalar defaults to string.
| GraphQL scalar | TypeScript type |
|---|---|
DateTime, Date, Time, DateTimeOffset |
Date |
Decimal, Long, BigInt, ULong, UInt, Short, Byte |
number |
UUID, Guid, Email, URL, URI |
string |
Use --custom-scalar to override the TS type emitted for a scalar. Repeatable. Unsupported targets are hard errors — no silent fallbacks.
| Target | Emitted TS type |
|---|---|
string |
string |
number |
number |
boolean |
boolean |
Date |
Date |
npx @metaengine/graphql-react schema.graphql ./src/api \
--custom-scalar DateTime=string \
--custom-scalar UUID=stringInteger-like scalars (
Long,BigInt,ULong) map tonumberby design so values carried in requestvariablessurviveJSON.stringify. Abiginttarget is therefore not offered.
Try the generator with your own schema at https://www.metaengine.eu/converters.
The NuGet package allows programmatic use in .NET projects. See the website documentation for full C# API reference.
- Issues: GitHub Issues
- Email: info@metaengine.eu
- Website: metaengine.eu
MIT License - see LICENSE file for details.
This is the documentation and issue tracking repository for MetaEngine GraphQL React. The compiled NPM package is available at @metaengine/graphql-react.
Source code is proprietary, but the package is free to use under MIT license.