Summary
I've built and published a working implementation of Argo —
a formally specified, production-proven (WhatsApp, Beeper) binary serialization format for
GraphQL responses — as a set of Spring Boot starters on top of spring-graphql. Before I put
more work into it, I'd like maintainer input on whether this is something you'd want as a
first-party module, or whether it's better as an independent library you'd link to from the docs
as a community extension. Either answer is useful to me; I mainly want to avoid guessing wrong
about scope.
What Argo is, briefly
Argo derives a compact "wire schema" per persisted query and encodes responses against it — not
a naive hand-rolled binary format. It gets unions/interfaces/fragments/@skip/@include right
by construction, keeps null/absent/error as three distinct wire states (JSON conflates the first
two), and routes scalar values into per-type columnar blocks specifically so it still beats
compressed JSON, not just raw JSON. Spec + rationale: the linked site, and Mike Solomon's
GraphQLConf 2023 talk ("Argo: Designing a Compact and Compressible Binary Serialization Format
for GraphQL").
What exists today
Three modules, published to Maven Central under io.github.giridhargg (repo: https://github.com/giridhargg/spring_argo_gql):
gql-argo-core — wire-format primitives (WireType, ArgoEncoder, ArgoDecoder,
ArgoSchemaSerializer), independent of Spring.
gql-argo-server-starter — installs as a WebGraphQlInterceptor that fires after your
existing resolvers; requests with Accept: application/argo get binary responses, everything
else is untouched. Includes persisted-query registration/schema endpoints and extension points
(ArgoPersistedQueryStore, ArgoSchemaCustomizer, ArgoEncodingCustomizer).
gql-argo-client-starter — client-side counterpart; works with RestClient, WebClient
(blocking and reactive), and RestTemplate.
No changes to application resolver code are required — it's purely a transport-layer addition.
Evidence, not just a pitch
I audited the implementation against the GraphQL spec and Argo's own wire-format checklist
feature-by-feature (results in FEATURE_COVERAGE.md in the repo) rather than assuming coverage
from docs. Solid: all value kinds, nullability (including field-omitted vs. field-present-null as
genuinely distinct wire states), lists (including million-element, non-stack-growing encoding),
interfaces/unions preserving concrete type, aliases, fragments, directives, errors with full
message/locations/path/extensions, partial success, subscriptions (real, WebSocket-based),
introspection, Relay conventions. Explicitly out of scope / not implemented: binary request
encoding (Argo's spec itself only covers responses), @defer/@stream, batch requests, file
uploads, federation.
Benchmarked, not asserted — two separate measurements:
Wire size (WireSizeComparisonTest, raw byte lengths, JSON vs. Argo, uncompressed and
gzipped):
| Shape |
JSON+gzip |
Argo+gzip |
Argo+gzip vs. JSON+gzip |
| List of 10,000 |
83,924 B |
71,584 B |
14.7% smaller |
| Nested (2,000 orders × 20 items) |
17,119 B |
7,153 B |
58.2% smaller |
| Deeply nested (4 levels) |
4,201 B |
2,616 B |
37.7% smaller |
(Full 7-shape table, including the honest counter-case where gzip's own overhead dominates for
tiny single-record payloads, is in the repo.)
Encode/decode CPU cost (JMH, gql-argo-benchmarks, vs. Jackson): decoding is a consistent
15–43% faster than Jackson deserialize from a single record through 2,000 nested orders, since it
skips string parsing/escaping entirely. Encoding is a genuine tradeoff, not a clean win — slower
than Jackson for flat homogeneous lists (columnar-block bookkeeping overhead), faster for
broad-but-shallow nested shapes (23–34%), roughly even for deeply nested ones. I've documented
this honestly rather than cherry-picking the favorable numbers — full writeup with methodology
caveats in the repo's BLOG.md.
The scope question
spring-graphql's core is deliberately narrow, and I know new wire formats + a persisted-query
registry + two new starter modules is a substantial addition, not a small patch. So concretely,
I'd like your read on:
- Is a first-party binary transport something in scope for this project at all, or is that
better left to satellite libraries by design?
- If in scope in principle: would you want it as-is (roughly, adopting these three modules), or
would the shape need to change significantly to fit your conventions/maintenance model?
- If out of scope: would you be open to linking
gql-argo from the docs (e.g. an "extensions/
community" section) so people evaluating binary transports can find it?
Happy to do the work either way — adapt the modules to fit your conventions, split things up
differently, or just keep maintaining it independently with a docs link. I'd rather get a scope
answer before writing a PR than have a large one show up unsolicited.
Repo:https://github.com/giridhargg/spring_argo_gql
Maven Central: io.github.giridhargg:gql-argo-core / gql-argo-server-starter /
gql-argo-client-starter
Summary
I've built and published a working implementation of Argo —
a formally specified, production-proven (WhatsApp, Beeper) binary serialization format for
GraphQL responses — as a set of Spring Boot starters on top of
spring-graphql. Before I putmore work into it, I'd like maintainer input on whether this is something you'd want as a
first-party module, or whether it's better as an independent library you'd link to from the docs
as a community extension. Either answer is useful to me; I mainly want to avoid guessing wrong
about scope.
What Argo is, briefly
Argo derives a compact "wire schema" per persisted query and encodes responses against it — not
a naive hand-rolled binary format. It gets unions/interfaces/fragments/
@skip/@includerightby construction, keeps null/absent/error as three distinct wire states (JSON conflates the first
two), and routes scalar values into per-type columnar blocks specifically so it still beats
compressed JSON, not just raw JSON. Spec + rationale: the linked site, and Mike Solomon's
GraphQLConf 2023 talk ("Argo: Designing a Compact and Compressible Binary Serialization Format
for GraphQL").
What exists today
Three modules, published to Maven Central under
io.github.giridhargg(repo: https://github.com/giridhargg/spring_argo_gql):gql-argo-core— wire-format primitives (WireType,ArgoEncoder,ArgoDecoder,ArgoSchemaSerializer), independent of Spring.gql-argo-server-starter— installs as aWebGraphQlInterceptorthat fires after yourexisting resolvers; requests with
Accept: application/argoget binary responses, everythingelse is untouched. Includes persisted-query registration/schema endpoints and extension points
(
ArgoPersistedQueryStore,ArgoSchemaCustomizer,ArgoEncodingCustomizer).gql-argo-client-starter— client-side counterpart; works withRestClient,WebClient(blocking and reactive), and
RestTemplate.No changes to application resolver code are required — it's purely a transport-layer addition.
Evidence, not just a pitch
I audited the implementation against the GraphQL spec and Argo's own wire-format checklist
feature-by-feature (results in
FEATURE_COVERAGE.mdin the repo) rather than assuming coveragefrom docs. Solid: all value kinds, nullability (including field-omitted vs. field-present-null as
genuinely distinct wire states), lists (including million-element, non-stack-growing encoding),
interfaces/unions preserving concrete type, aliases, fragments, directives, errors with full
message/locations/path/extensions, partial success, subscriptions (real, WebSocket-based),
introspection, Relay conventions. Explicitly out of scope / not implemented: binary request
encoding (Argo's spec itself only covers responses),
@defer/@stream, batch requests, fileuploads, federation.
Benchmarked, not asserted — two separate measurements:
Wire size (
WireSizeComparisonTest, raw byte lengths, JSON vs. Argo, uncompressed andgzipped):
(Full 7-shape table, including the honest counter-case where gzip's own overhead dominates for
tiny single-record payloads, is in the repo.)
Encode/decode CPU cost (JMH,
gql-argo-benchmarks, vs. Jackson): decoding is a consistent15–43% faster than Jackson deserialize from a single record through 2,000 nested orders, since it
skips string parsing/escaping entirely. Encoding is a genuine tradeoff, not a clean win — slower
than Jackson for flat homogeneous lists (columnar-block bookkeeping overhead), faster for
broad-but-shallow nested shapes (23–34%), roughly even for deeply nested ones. I've documented
this honestly rather than cherry-picking the favorable numbers — full writeup with methodology
caveats in the repo's
BLOG.md.The scope question
spring-graphql's core is deliberately narrow, and I know new wire formats + a persisted-queryregistry + two new starter modules is a substantial addition, not a small patch. So concretely,
I'd like your read on:
better left to satellite libraries by design?
would the shape need to change significantly to fit your conventions/maintenance model?
gql-argofrom the docs (e.g. an "extensions/community" section) so people evaluating binary transports can find it?
Happy to do the work either way — adapt the modules to fit your conventions, split things up
differently, or just keep maintaining it independently with a docs link. I'd rather get a scope
answer before writing a PR than have a large one show up unsolicited.
Repo:https://github.com/giridhargg/spring_argo_gql
Maven Central: io.github.giridhargg:gql-argo-core / gql-argo-server-starter /
gql-argo-client-starter