Genql Runtime

The zero-dependency runtime engine behind Genql's type-safe GraphQL client, handling query generation, batching, and error parsing.

Library
npm
v2.10.0
977stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
51/100Fair
Development Activity28
Maintenance36
Community40
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
75/100Good
Architecture80
Code Quality65
Innovation80
Learning Curve75

@genql/runtime is the execution engine that powers every client generated by the Genql CLI. It takes the field-selection objects you write in TypeScript — plain nested objects like { countries: { name: true } } — and turns them into real GraphQL query strings and variables, without ever touching the graphql package or parsing a query AST at runtime.

Beyond query generation, the runtime provides a pluggable fetcher (createFetcher), an automatic request batcher (QueryBatcher) that coalesces same-tick queries into a single network round trip, and a typed GenqlError class that surfaces partial data and GraphQL error arrays instead of throwing generic errors. Because it’s the only piece a generated Genql client depends on at runtime, it ships with zero dependencies and works unmodified in browsers, Node.js, Deno, Cloudflare Workers, and Bun.

What You Get

  • A createClient factory that wires a fetcher to typed query/mutation methods
  • generateGraphqlOperation, which walks a nested field-selection object and compiles it into a GraphQL query string plus variables
  • A built-in QueryBatcher that coalesces same-tick requests into one HTTP call within a configurable interval and max batch size
  • A typed GenqlError class carrying the server’s GraphQL error array and any partial data
  • linkTypeMap, which dereferences the CLI’s compressed schema map into the linked type tree the operation generator needs

Common Use Cases

  • Powering the client produced by genql --schema ./schema.graphql --output ./generated, so consumers never hand-write GraphQL
  • Batching many small queries issued during a single render pass into one network request
  • Swapping the default fetch-based transport for a custom fetcher to add auth headers, retries, or route through a different HTTP client
  • Catching partial-success GraphQL responses via GenqlError.data instead of losing the response entirely on error

Under The Hood

Architecture The runtime is a lean, single-purpose library split into decoupled units: generateGraphqlOperation.ts walks the nested field-selection object depth-first to emit a GraphQL query string plus a variables map, delegating type and argument resolution to getFieldFromPath against a LinkedType tree; createClient.ts is a thin factory that wires a fetcher (from fetcher.ts) to query/mutation entrypoints, deferring all typing to consumer-generated code; fetcher.ts wraps a user-supplied or default fetch implementation, optionally routing through batcher.ts’s QueryBatcher, which coalesces same-tick requests into a single POST within a configurable batchInterval/maxBatchSize window and fans responses back out to individual promises; linkTypeMap.ts performs a one-time transform of the CLI’s compressed, index-based schema representation into a fully dereferenced LinkedTypeMap so the operation generator can walk it directly at request time. There’s no internal state beyond the batch queue and no dependency injection — a pure functional pipeline (type map -> operation string -> fetch -> parsed result) — so changing the compressed type-map wire format mostly touches linkTypeMap.ts and generateGraphqlOperation.ts alone.

Tech Stack Zero runtime dependencies — the README advertises “no dependencies (not even graphql)” — pure TypeScript targeting ES2015/CommonJS via tsc, published as part of the @genql/cli build pipeline with declaration files and source maps. It relies only on the global fetch (or a user-supplied polyfill) for network I/O, no bundled HTTP client. The monorepo is managed with pnpm workspaces plus Lerna for publishing and Changesets for versioning; the runtime historically shipped as its own npm package and is now maintained as internal src/runtime templates inside the @genql/cli source tree.

Code Quality There are no dedicated test files inside the runtime’s own source directory, but typeSelection.test.ts at the CLI package root directly exercises the recursive FieldsSelection conditional-type logic the runtime re-exports, and the broader test suite (printer.test.ts, render/**/__tests__, utils.test.ts) covers the code-generation half of the pipeline that produces the LinkedTypeMap the runtime consumes at request time. GitHub Actions CI is configured, and the package compiles under full strict TypeScript. Error handling is explicit and typed through the dedicated GenqlError class rather than generic throws, and file-per-concern naming keeps each module’s surface small. No standalone linter configuration was found at the repo root beyond the compiler’s own type checking.

API Design createClient needs only a URL, fetcher, or headers to return typed query/mutation methods generated by the sibling CLI, so getting started requires no manual wiring beyond running the code generator once. Consumers write plain nested field-selection objects instead of hand-written GraphQL strings, and the __scalar: true sentinel lets an entire scalar subtree be requested without enumerating every field. The public surface is intentionally tiny — createClient, everything, GenqlError, createFetcher, generateGraphqlOperation, linkTypeMap — with JSDoc comments on the batching class documenting each option alongside a runnable example. The one source of friction is that the runtime alone is inert without first running the genql CLI to produce the typed schema it depends on.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search