What is nanopb?nanopb is a Protocol Buffers implementation specifically designed for resource-constrained devices (such as microcontrollers and IoT chips). It is written entirely in ANSI C, with a code size of just a few KB, consuming almost no memory, and boasts excellent compiler compatibility. Want to efficiently transfer structured data between an MCU and a server? nanopb can help you achieve that.
What pain points does it address?
| Pain Point | Traditional Approach | Benefits of nanopb |
| Large code size | The official protobuf C++ implementation is over several hundred KB | Only a few KB, suitable for chips with 32 KB Flash |
| Many runtime dependencies | Requires dynamic memory and complex libraries | Completely based on static allocation, zero heap |
| Cross-platform portability issues | Compiler features are not uniform, high porting costs | Pure ANSI C, can be compiled by almost all compilers |
| Manual serialization is cumbersome | Handwritten byte streams are prone to errors | Automatically generates .pb.c/.pb.h, with one-click encoding and decoding API calls |
| Debugging difficulties | Binaries are not easily readable, slow error localization | Supports optional debug macros to print field names for quick localization |
Installation & Environment Setup
- 1. Download the source code or binary package
git clone https://github.com/nanopb/nanopb.git # Or directly download the precompiled zip package - 2. Prepare protoc and plugins
- • The official packages for Windows/macOS/Linux already include
<span>protoc</span>and<span>nanopb_generator</span>. - • If compiling yourself, you need to install Python +
<span>pip install protobuf grpcio-tools</span>.
<span>pb_encode.c pb_decode.c pb_common.c</span> into your project directory, ensuring the compiler can find them.Tip: If you are using PlatformIO, CMake, or Makefile, nanopb has already provided corresponding templates (in the
<span>extra/</span>directory), just copy-paste them.
Quick Start: One-Step Completion
- 1. Write .proto (for example,
<span>msg.proto</span>)syntax = "proto2"; message SensorData { required uint32 id = 1; required float temp = 2; optional bool alarm = 3 [default = false]; } - 2. Generate code
python generator/nanopb_generator.py msg.proto # Generates msg.pb.c / msg.pb.h - 3. Call in your code
#include "msg.pb.h" // Encoding SensorData data = SensorData_init_default; data.id = 123; data.temp = 36.5f; uint8_t buffer[64]; pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); bool ok = pb_encode(&stream, SensorData_fields, &data); // stream.bytes_written contains the serialized bytes // Decoding SensorData recv = SensorData_init_default; pb_istream_t istream = pb_istream_from_buffer(buffer, stream.bytes_written); ok = pb_decode(&istream, SensorData_fields, &recv);With just a few lines, the structure directly maps to protobuf, making it easy and efficient.
Overview of Advantages and Disadvantages
| Advantages | Disadvantages |
| Very small footprint: a few KB of code, suitable for low-end MCUs | Incomplete functionality: does not support advanced features of proto3 such as all-optional and map |
| No heap: fully statically allocated, safe and reliable | Generates many files: each .proto generates .pb.c/.pb.h, leading to code bloat |
| Cross-platform: can be compiled by almost all C compilers | Learning curve: needs understanding of .proto syntax and nanopb options file |
Customizable: controls field compression, default values, etc. via <span>.options</span> |
Debug information must be manually enabled: debug macros are off by default, error localization needs to be manually turned on |
| Rich ecosystem: complete integration scripts for CMake, Make, PlatformIO, Arduino, etc. | No support for C++ class encapsulation: can only use C API, object-oriented programming requires manual encapsulation |
Conclusion
nanopb is truly a protobuf version tailored for embedded systems. It compresses a protocol that was originally only usable on servers and PCs into a few KB C library, allowing microcontrollers to easily implement structured communication. Although it does not support the latest advanced features of proto3, it is already powerful enough for most IoT, sensor, and Bluetooth scenarios. Once you master the steps of writing and generating <span>.proto</span>, the subsequent encoding/decoding is almost a straightforward operation—saving time, effort, and memory.
If you are struggling with data interaction between MCUs and the cloud, or want to add a reliable serialization solution to your Arduino/ESP32 projects, nanopb is worth a try. Once you try it out, when the code runs, you will realize: embedded systems can also master “protocol buffers”!
Project address: https://github.com/nanopb/nanopb