Skip to content

RFC 008: Server compression preference - #405

Open
anuraaga wants to merge 13 commits into
connectrpc:mainfrom
anuraaga:rfc-server-compression
Open

RFC 008: Server compression preference#405
anuraaga wants to merge 13 commits into
connectrpc:mainfrom
anuraaga:rfc-server-compression

Conversation

@anuraaga

Copy link
Copy Markdown
Contributor

Introduce RFC 008, which proposes to move compression preference from client to server.
This allows using modern compression methods with connect-web and follows the general ecosystem.

The concrete changes proposed are in #322

@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown

@anuraaga is attempting to deploy a commit to the connectrpc Team on Vercel.

A member of the Team first needs to authorize it.

Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
@anuraaga
anuraaga force-pushed the rfc-server-compression branch from a51e222 to 62de975 Compare August 28, 2026 02:03
Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
connect Ready Ready Preview Sep 1, 2026 2:50am UTC

Request Review

Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
Comment thread src/content/docs/docs/governance/rfc/008-server-compression-preference.md Outdated
Comment thread src/content/docs/docs/governance/rfc/008-server-compression-preference.md Outdated
@nicksnyder
nicksnyder requested a review from timostamm August 28, 2026 17:58
anuraaga and others added 2 commits August 31, 2026 14:47
Co-authored-by: Nick Snyder <nickdsnyder@gmail.com>
Signed-off-by: Anuraag (Rag) Agrawal <anuraaga@gmail.com>
Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>

@timostamm timostamm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading through protocol.md, I noticed that Unary-Get-Request still asserts the previous behavior, and I believe that it needs to change, following that same rationale (see the exact location in #322 (review)).

Two more suggestions for this RFC:

Comment thread src/content/docs/docs/governance/rfc/008-server-compression-preference.md Outdated
Comment thread src/content/docs/docs/governance/rfc/008-server-compression-preference.md Outdated
Comment thread src/content/docs/docs/governance/rfc/008-server-compression-preference.md Outdated
Comment thread src/content/docs/docs/governance/rfc/008-server-compression-preference.md Outdated
Comment thread src/content/docs/docs/governance/rfc/008-server-compression-preference.md Outdated
Comment on lines +19 to +23
- The list of supported compression methods configured on the server
- The list of supported compression methods in the client's `Accept-Encoding` header, e.g., `gzip, br, zstd`

Currently, it is the order in the `Accept-Encoding` header that determines which
algorithm to prefer. The server chooses the first compression method that it supports.

@emcfarlane emcfarlane Aug 31, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In connect-go the response compression is chosen to match the request: https://github.com/connectrpc/connect-go/blob/51112608939254772c8e67577eb5b353741aaa7e/protocol.go#L308-L311

This seems to not be defined in the Spec.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out! It seems most intuitive to match the request when the request is compressed. Connect-Py currently does not, since I think I was reading the spec closely when implementing that.

This seems like the right time to consolidate this behavior. I have added a note to use the request compression when provided.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. This needs to be specified in protocol.md. It currently says that servers should not do that. I'll suggest a change.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops I had updated the RFC here but forgot to update the protocol.md PR, updated it

006519b

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, I'm not sure if they should do this behavior. But the current connect-go does, and I wanted clarification so implementations are consistent.

anuraaga and others added 6 commits September 1, 2026 11:36
…eference.md

Co-authored-by: Nick Snyder <nickdsnyder@gmail.com>
Signed-off-by: Anuraag (Rag) Agrawal <anuraaga@gmail.com>
…eference.md

Co-authored-by: Edward McFarlane <3036610+emcfarlane@users.noreply.github.com>
Signed-off-by: Anuraag (Rag) Agrawal <anuraaga@gmail.com>
Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
unlocking them for connect-web. Servers like Envoy and NGINX behave in the same way for the
same reason.

While `br` and `zstd` have come a long way and commonly have similar CPU and RAM usage to

@sudorandom sudorandom Sep 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's something to mention here in regard to Brotli. The official reference library defaults to a compression level of 11 (out of 11). That's level uses A LOT of CPU. And so little-by-little languages are starting to switch the default, but it seems like a lot have not gotten the memo:

And with load balancers, almost none of them use the high default:

I don't think there's anything to do here immediately, but I wanted this to be known about. Defaults are super important for things like this. I suspect documentation of the server compression priority for each language is where this is useful.

From my experiments, brotli compression at level 11 uses so much CPU that the expected RPS for a typical app service will plummet.

While br and zstd have come a long way and commonly have similar CPU and RAM usage to gzip now

when configured appropriately.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup we aligned with Envoy in connect-py

connectrpc/connect-py#97

I'm not going to complicate the prose for that here though. If we want to add compression levels to the spec, probably another PR that doesn't necessarily need an RFC (maybe)

emcfarlane added a commit to connectrpc/connect-go that referenced this pull request Sep 10, 2026
This PR moves codec and compressor configuration from additive options
to authoritative slices (`WithCodecs` and `WithCompressors`). This
resolves a few historical API limitations and lets the caller state the
preference order directly.

Compression negotiation is unchanged. The server still responds with the
client's first supported entry, matching v1. The recent spec update
connectrpc/connectrpc.com#405 would let the
server choose the response encoding instead, which matters because
browsers hardcode `Accept-Encoding: gzip, deflate, br, zstd` and can
never negotiate past `gzip` under the current rule. That spec change
isn't ready for v2, so it's left out here. The ordered slices are the
piece it needs, so it can land on top later without another API break.

Ordering was the underlying problem. Additive options made the
preference order implicit in registration order, and the most recently
registered compressor was the most preferred, which reads backwards.
`WithCompressors` and `WithCodecs` now replace the defaults, and the
order you provide in the slice is exactly what gets advertised. It
applies to both codecs and compressors for consistency and matches the
pattern in [connect-py](https://github.com/connectrpc/connect-py).

This simplifies the option API surface. Removes `WithAcceptCompression`,
registered compressors are now always advertised, and removes
`WithNoCompression`, an empty `WithCompressors()` disables compressors.

Migration tool has been updated to warn on `connect.WithCodec`,
`WithCompression`, and `WithAcceptCompression` options. These aren't
mechanical translations and require review. For example, the conformance
tests set a custom JSON codec for a stricter encoding and has been
updated.

### Examples 

Compression preference in order:
```go
// Prefer brotli, fall back to gzip. Sends Accept-Encoding: br,gzip
connecthttp.WithCompressors(brotli, connectgzip.New())
```

Removing the default JSON codec was previously impossible:
```go
// Serve binary Protobuf only.
connecthttp.Mount(mux, srv, connecthttp.WithCodecs(connectproto.NewBinaryCodec()))
```

Client prefer the first registered codec, so looses the need to always
set these two options:
```go
// before
connecthttp.WithCodec(jsonCodec), connecthttp.WithSendCodec(jsonCodec.Name())
// after
connecthttp.WithCodecs(jsonCodec)
```

---------

Signed-off-by: Edward McFarlane <3036610+emcfarlane@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants