HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
protocolbuffers
protobuf
C++2014–2026
protocolbuffers / protobuf

protobuf

Protocol Buffers - Google's data interchange format

89Distinct people
124Mentions
0Explicit recommenders
72.2KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

Protocol Buffers - Google's data interchange format

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

No recommendation phrase was found in the indexed comments.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

No other repository is repeatedly linked in the same discussions.

This week on Hacker News

Nov 8–Nov 15 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/15/2026, 5:03:38 AM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year124 dated mentions

Observed mentions: 2014-12-15 12:38:35 UTC to 2026-10-09 18:07:50 UTC.

0510152014-01-01 00:00:00 UTC to 2015-01-01 00:00:00 UTC (exclusive): 1 mentions; 1 submissions, 0 comments20142015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 11 mentions; 2 submissions, 9 comments2016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 11 mentions; 3 submissions, 8 comments2017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 12 mentions; 0 submissions, 12 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 13 mentions; 0 submissions, 13 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 14 mentions; 1 submissions, 13 comments20202021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 7 mentions; 0 submissions, 7 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 6 mentions; 0 submissions, 6 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 8 mentions; 1 submissions, 7 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 14 mentions; 2 submissions, 12 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 15 mentions; 1 submissions, 14 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 7 mentions; 0 submissions, 7 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20142014-01-01 00:00:00 UTC2015-01-01 00:00:00 UTC110
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC1129
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC1138
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC505
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC12012
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC13013
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC14113
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC707
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC606
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC817
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC14212
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC15114
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC707

From the project README

An excerpt from the repository, fetched Nov 13, 2026.

Read the project’s introduction
Protocol Buffers - Google's data interchange format Copyright 2008 Google LLC Overview Protocol Buffers (a.k.a., protobuf) are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data. You can learn more about it in protobuf's documentation. This README file contains protobuf installation instructions. To install protobuf, you need to install the protocol compiler (used to compile .proto files) and the protobuf runtime for your chosen programming language. Working With Protobuf Source Code Most users will find working from supported releases to be the easiest path. If you choose to work from the head revision of the main branch your build will occasionally be broken by source-incompatible changes and insufficiently-tested (and therefore broken) behavior. If you are using C++ or otherwise need to build protobuf from source as a part of your project, you should pin to a release commit on a release branch. This is because even release branches can experience some instability in between release commits. Bazel with Bzlmod Protobuf supports Bzlmod with Bazel 8 +. Users should specify a dependency on protobuf in their MODULE.bazel file as follows. bazel_dep(name = "protobuf", version = <VERSION>) Users can optionally override the repo name, such as for compatibility with WORKSPACE. bazel_dep(name = "protobuf", version = <VERSION>, repo_name = "com_google_protobuf") Bazel with WORKSPACE Users can also add the following to their legacy WORKSPACE file. Note that with the release of 30.x there are a few more load statements to properly set up rules_java and rules_python. http_archive( name = "com_google_protobuf", strip_prefix = "protobuf-VERSION", sha256 = ..., url = ..., ) load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") protobuf_deps() load("@rules_java//java:rules_java_deps.bzl", "rules_java_dependencies") rules_java_dependencies() load("@rules_java//java:repositories.bzl", "rules_java_toolchains") rules_java_toolchains() load("@rules_python//python:repositories.bzl", "py_repositories") py_repositories() Protobuf Compiler Installation The protobuf compiler is written in C++. If you are using C++, please follow the C++ Installation Instructions to install protoc along with the C++ runtime. For non-C++ users, the simplest way to install the protocol compiler is to download a pre-built binary from our GitHub release page. In the downloads section of each release, you can find pre-built binaries in zip packages: protoc-$VERSION-$PLATFORM.zip. It contains the protoc binary as well as a set of standard .proto files distributed along with protobuf. If you are looking for an old version that is not available in the release page, check out the Maven repository. These pre-built binaries are only provided for released versions. If you want to use the github main version at HEAD, or you need to modify protobuf code, or you are using C++, it's recommended to build your own protoc binary from source. If you would like to build protoc binary from source, see the C++ Installation Instructions. Protobuf Runtime Installation Protobuf supports several different programming languages. For each programming language, you can find instructions in the corresponding source directory about how to install protobuf runtime for that specific language: Language Source C++ (include C++ runtime and protoc) src Java java Python python Objective-C objectivec C# csharp Ruby ruby Go protocolbuffers/protobuf-go PHP php Dart dart-lang/protobuf JavaScript protocolbuffers/protobuf-javascript Quick Start The best way to learn how to use protobuf is to follow the tutorials in our developer guide. If you want to learn from code examples, take a look at the examples in the examples directory. Documentation The complete documentation is available at the Protocol Buffers doc site. Support Policy Read about our version support policy to stay current on support timeframes for the language libraries. Developer Community To be alerted to upcoming changes in Protocol Buffers and connect with protobuf developers and users, join the Google Group.
Read the full README on GitHub

What Hacker News says

15 sources
Protobuf is the example I had in mind. It uses sun.misc.Unsafe which is being removed in upcoming Java releases, but it has a slow fallback path. It logs a warning when it runs if it can tell it's only using the fallback path but the fast path is still available if the application owner set a flag to turn it back on if they want to: https://github.com/protocolbuffers/protobuf/issues/20760 Java Protobuf also logs a warning now if you can tell you are using gencode old enough that it's covered by a DoS CVE. They actually did a release that broke compatability of the CVE covered gencode but restored it and print a warning in a newer release.
In Log level 'error' should mean that something needs to be fixed
If I have a library that let me curry trailing arguments for a function, then I can see how something like std::flip() could be useful in letting me curry different arguments without costing extra lines of code. The library I had in mind is Google's RPC callbacks: https://github.com/protocolbuffers/protobuf/blob/main/src/go... This library was written in the C++98 era. It might seem silly now because with C++11, we could use std::bind or lambda expressions instead.
In `std::flip`
Out of curiosity, does this idiom work in fil-c? https://github.com/protocolbuffers/protobuf/blob/cb873c8987d... // This somewhat silly looking add-and-subtract behavior provides provenance // from the original input buffer's pointer. After optimization it produces // the same assembly as just casting `(uintptr_t)ptr+input_delta` // https://godbolt.org/z/zosG88oPn size_t position = (uintptr_t)ptr + e->input_delta - (uintptr_t)e->buffer_start; return e->buffer_start + position; It does use the implementation defined behavior that a char pointer + 1 casted to uintptr is the same as casting to uintptr then adding 1.
In Fil's Unbelievable Garbage Collector
I tried implementing an optimized varint encoder that did something similar, by populating an 8 byte value and then storing it to ram, but unaligned overlapping stores caused big regressions. The approach that worked required a different technique. This one is for encoding backwards: 1. One branch for the one-byte case, always inlined, just store the byte 2. Calculate the size size of the unencoded zero prefix with a branch-free construction: (((uint32_t)clz + 7) * 9) >> 6 3. Hand roll a jump table taking advantage of arm's fixed instruction width to calculate the jump target with a shift. https://github.com/protocolbuffers/protobuf/commit/b039dfe26... This results in one branch for 1 byte varints, plus one additional branch for any larger size, and the branch predictor does not have to track a varying trip count through a loop. This ap
Read the rest
proach resulted in a 2.64% speedup for overall encoding (which includes a lot more than just varints) on mid sized arm cores. I think it's very difficult to beat a single comparison and branch for the 1 byte case for actual encoding forwards or backwards, unless you know there's going to be long runs of one-byte values.
In I wasted weeks hand optimizing assembly because I benchmarked on random data
This kind of "expected next field" optimization has a long history in protobuf, but results are mixed. The generated code in C++ used to check for the expected next field before falling back to the switch() (example here: https://github.com/protocolbuffers/protobuf/blob/460e7dd7c47...) but this was removed in 2016 when load tests found that it hurt more than it helped. One tricky part of making this optimization work is making a good guess about what the next field should be. Miguel's article alludes to this: > Each field specifies which fields to try next. This allows the compiler to perform field scheduling, by carefully deciding which order to try fields in based both on their declaration order and a rough estimation of their “hotness”, much like branch scheduling happens in a program compiler. This avoids almost all of the work of lo
Read the rest
oking up the next field in the common case, because we have already pre-loaded the correct guess. > I haven’t managed to nail down a good algorithm for this yet, but I am working on a system for implementing a type of “branch prediction” for PGO, that tries to provide better predictions for the next fields to try based on what has been seen before. One delightful thing about the tail-call parser design is that the CPU's branch predictor effectively takes over the job of guessing. With a tail call parser, the dispatch sequence ends up looking like this: cmp QWORD PTR [rdi+0x8],rsi # Bounds check jbe .fallback movzx r10d,WORD PTR [rsi] # Load two bytes of tag mov eax,r10d and eax,0xf8 mov r9,QWORD PTR [rcx+rax*2] # Load table data xor r9,r10 mov rax,QWORD PTR [rcx+rax*2+0x8] # Load field parser function jmp rax # Tail call to field parser That "jmp rax" instruction is an indirect branch that can be predicted by the CPU. The CPU effectively guesses for us! And unlike any kind of guess we might have performed ahead-of-time, the branch predictor will constantly adapt to whatever patterns it is seeing in the data. This is good, because statically guessing ahead-of-time is hard.
In Parsing Protobuf like never before
I think I can shed some light on this, as the creator and lead of upb. Calling a Protobuf Parser an "interpreter VM" is a little bit of rhetorical flourish. It comes from the observation that there are some deep structural similarities between the two, which I first observed in an article a few years back: https://blog.reverberate.org/2021/04/21/musttail-efficient-i... > It may seem odd to compare interpreter loops to protobuf parsers, but the nature of the protobuf wire format makes them more similar than you might expect. The protobuf wire format is a series of tag/value pairs, where the tag contains a field number and wire type. This tag acts similarly to an interpreter opcode: it tells us what operation we need to perform to parse this field’s data. Like interpreter opcodes, protobuf field numbers can come in any order, so we have to
Read the rest
be prepared to dispatch to any part of the code at any time. This means that the overall structure of a protobuf parser is conceptually a while() loop surrounding a switch() statement, just like a VM interpreter. The tricky part is that the set of "case" labels for a Protobuf parser is message-specific and defined by the fields in the schema. How do we accommodate that? The traditional answer was to generate a function per message and use the schema's field numbers as the case labels. You can see an example of that here (in C++): https://github.com/protocolbuffers/protobuf/blob/f763a2a8608... More recently, we've moved towards making Protobuf parsing more data-driven, where each field's schema is compiled into data that is passed as an argument to a generic Protobuf parser function. We call this "table-driven parsing", and from my read of the blog article, I believe this is what Miguel is doing with hyperpb. The trick then becomes how to make this table-driven dispatch as fast as possible, to simulate what the switch() statement would have done. That question is what I cover at length in the article mentioned above.
In Parsing Protobuf like never before
> Would be great if you report such remote code executions to the authors/Google. I am sure they handle CVEs etc. I wasn't getting paid to fix their code, I have no interest in helping Google for free, and don't want to help Google. > There has been a security audit like A checkbox report from six years ago. That's ancient times at the pace that things are added to gRPC. > Are you making shit up as you go? No. This [0] repo I used to reproduce a stack smash issue before `main()`. I reported the issue here [1]. I don't get paid to fix Google's things and found a workaround for the purposes I needed. [0]: https://github.com/keith-bennett-airmap/grpc-stacksmash [1]: https://github.com/protocolbuffers/protobuf/issues/12732 > I can see various fuzzers in the code base so that claim is also unsubstantiated Fuzzers are cool, but they don't cover
Read the rest
the whole codebase.
In Show HN: BinaryRPC – Lightweight WebSocket-based RPC framework in modern C++
>This is actually a good (albeit somewhat niche) reason to not write a test scenario at all, but it's still not a great reason to write a test after instead of before. But the before-test is strictly negative - it's a waste of time (deleted code, never submitted) and it possibly slowed down development (had to update the test as I messed with APIs). >Yup. A test scenario which is of no interest to at least some stakeholders probably shouldnt be written at all. And yet I see TDD practitioners as the primary source of such tests - if you are dogmatically writing a test for every intermediate change, you will end up with lots of extra tests that assert things in order to satisfy the TDD dogma rather than the specific needs of the problem. Obviously this can be avoided with judgement - but if you have sound independent judgement you don't nee
Read the rest
d to adhere to specific philosophies about the order you make changes in. >In fact it's probably a bit easier to link intentional behavior to a test while you have the spec in front of you and before the code is written. When implementing to a spec you are absolutely right, but a very small amount of software is completely or even mostly specified in advance. >I find people who write test after tend to (not always, but strong tendency) fit the test to the code rather than the requirement. This is really bad. I agree this can lead to brittle tests and lack of spec adherence, but if you are iterating on intermediate state and writing tests as you go, the structure of the code you wrote 30 seconds ago is very much influencing the test you're writing now. Another issue is that fault injection tests basically require coupling to the implementation - "make the Nth allocation fail" etc. The way I prefer to write these is to write the implementation first, then write the fuzz test - add a few bugs in the implementation, and fix/enhance the fuzz test until it catches them. Fuzz testing is one of the best bang-for-buck testing methodologies there is, and in my experience it's very hard to write a really good fuzz test unless you already have most of your implementation, so you can ensure your fuzz tester is actually exercising the stuff you want it to. >Assuming Im understanding you correctly (you're building something like terraform?), I write library code for mobile phones, mostly in Java/Kotlin. I recently did some open source work (warning: I am not actually very proficient with C, any good results are from enormous time spent and my code reviewers, constructive criticism very much welcome). Here's a few somewhat small, contained changes of mine, so we can talk about something concrete: https://github.com/protocolbuffers/protobuf/pull/19893/files This change alters a lock-free data structure to add a monotonicity invariant, when the space allocated is queried on an already-fused arena while racing with another fuse. I didn't add tests for this - I spent a fair bit of time thinking about how to do it, and decided that the type of test I would have to write to reliably reproduce this was not going to be net better at preventing a future bug, given its cost, than a comment in the implementation code and markdown documentation of the data structure. I don't know how I would really have made this change with a TDD methodology. https://github.com/protocolbuffers/protobuf/pull/19933/files This change moves a memory layout - again, I don't know how I would have written a test for this, besides something wild like querying smaps (not portable) to see if the final page of the arena allocation had faulted in. https://github.com/protocolbuffers/protobuf/pull/19885/files This change was written more in the way you recommend - but the whole change is basically a test. I debugged this by reading the code and thinking about it, then wrote up a pretty complicated fuzz test to help find any future races. I'm guessing that you would not consider adding debug asserts to be a violation of "write the test first"? So in this case, I followed TDD's order - not because I was following TDD, but because the code change was trivial and all the hard work was thinking about the data structures and memory model. https://github.com/protocolbuffers/protobuf/pull/19688/files All the tests were submitted before the implementation change here, but not because of TDD - in this case, I was trying to optimize performance, and wrote the whole implementation before any new tests - because changing the implementation required changing the API to no longer expose contiguous memory. But I did not want to churn all the users of the public API unless I knew my implementation was actually going to deliver a performance improvement - so I didn't write any tests for the API until I had the implementation pretty well in hand. Good thing too, because I actually had to alter the new API's behavior a few times to enable the performance I wanted, and if I had written all the tests as I went along, I'd have to go and rewrite them over and over. So in this case I wrote the implementation, got it how I wanted it, wrote and submitted the new API (implemented at first on the old implementation) and added tests, updated all callers to the new API, and then submitted the new implementation. I don't think TDD would have led to better results in these cases, but you sound like a TDD believer and I'm always interested to hear anything that would make my engineering better.
In The Big TDD Misunderstanding (2022)

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.