COOLJAPAN
← All posts

OxiProto 0.1.3 — Pure-Rust Protocol Buffers, with the protoc binary deleted

OxiProto is the COOLJAPAN Pure-Rust Protocol Buffers stack — a native .proto parser, codegen, and wire runtime that replaces the protoc C++ compiler. No protoc binary, no build-time C++, no -sys crates. Proto2 + proto3, multi-file imports, reflection, JSON, and a CLI, all part of the NoFFI sovereign Rust stack.

release oxiproto pure-rust cooljapan noffi protobuf serialization codegen grpc

The protobuf toolchain just lost its C++ dependency.

Today we’re releasing OxiProto 0.1.3 — the COOLJAPAN Pure-Rust Protocol Buffers stack: a native .proto parser, code generator, and wire runtime that you can drop into [build-dependencies] and never think about protoc again.

No protoc. No FFI. No -sys crates. No apt-get install protobuf-compiler. Pure Rust from the .proto file all the way to the encoded bytes.

Why OxiProto

Protocol Buffers are everywhere — gRPC services, event streams, config formats, on-disk records. But in Rust, every one of those use cases historically dragged in the same hidden prerequisite: the protoc C++ compiler binary, sitting on PATH, demanded by prost-build and tonic-build at build time.

That single requirement quietly poisons a lot of pipelines. A stock rust:slim container can’t build your crate until you bolt on a system package. Cross-compilation needs a pre-stage. CI images grow. Reproducibility suffers, because now your build depends on whatever protoc version the host happens to ship. And it’s all for a step that is, conceptually, just parsing a text grammar and emitting some structs.

OxiProto removes that step. A consumer with oxiproto = "0.1.3" in [build-dependencies] regenerates protobuf bindings on a stock rust:slim image — no protobuf compiler, no cross-compile pre-stage, no Bazel toolchain. All .proto parsing and descriptor construction runs through a native pure-Rust parser, and the already-pure prost runtime is re-exported as the wire-format engine.

This is the NoFFI thesis applied to serialization: take a piece of infrastructure that everyone assumed had to be C++, and rebuild it in memory-safe Rust so the default build is a single toolchain with no native dependencies.

What we built

OxiProto is a small workspace of focused crates. Each one does one layer of the protobuf stack, and the top-level oxiproto facade re-exports them behind feature flags so you only compile what you use.

1. Core types and the native wire format — oxiproto-core The foundation: a complete varint / zigzag / tag / fixed / length-delimited codec in oxiproto-core::wire, independent of prost. It’s no_std + alloc compatible when you turn off the default std feature. This crate also defines the OxiMessage, OxiName, and OxiOneof traits and the Extensions machinery.

2. The build helper — oxiproto-build The crate you put in [build-dependencies]. It turns .proto files into a FileDescriptorSet using a native pure-Rust parser by default, with protox (also pure Rust) as a fallback. The native parser handles proto2 and proto3, multi-file import resolution, source_code_info, custom options, and group desugaring.

3. Codegen — oxiproto-codegen Generates plain Rust structs and enums — plus optional impl OxiMessage blocks — directly from a FileDescriptorSet. Maps, oneofs, Default, services, doc comments, and JSON support are all covered.

4. Reflection — oxiproto-reflect Runtime reflection via a prost-reflect facade plus a native DescriptorPool and DynamicMessage, so you can inspect and manipulate messages whose types you don’t know at compile time.

5. Well-Known Types — oxiproto-wkt Interop for the standard WKTs: Timestamp, Duration, Any, Struct, FieldMask, and the scalar wrappers, with optional chrono interop.

6. JSON — oxiproto-json The canonical Protobuf-JSON mapping: camelCase field names, base64-encoded bytes, RFC 3339 timestamps.

7. CLI — oxiproto-cli A standalone command-line tool with gen, describe, encode, decode, format, lint, breaking, and doc subcommands — a protoc-free way to drive code generation and inspect schemas from the shell.

Getting Started

Add the runtime to your dependencies and the build helper to your build dependencies:

[dependencies]
oxiproto = "0.1.3"

[build-dependencies]
oxiproto-build = "0.1.3"

Then compile your schemas in build.rs — no protoc anywhere:

fn main() {
    oxiproto_build::compile_protos(&["proto/my_service.proto"], &["proto/"]).unwrap();
}

Prefer to compile a schema inline (great for tests and tooling)? Use the string API, which returns a FileDescriptorSet:

use oxiproto_build::compile_str;

let fds = compile_str(r#"
    syntax = "proto3";
    message Foo { string name = 1; }
"#)?;

And if you just want to encode and decode bytes by hand, the native wire codec stands on its own:

use oxiproto_core::wire::{EncodeBuffer, DecodeBuffer, encode_varint};

let mut buf = EncodeBuffer::new();
encode_varint(300, &mut buf.inner_mut());
let bytes = buf.into_bytes();

let mut decode = DecodeBuffer::from_bytes(&bytes);
let value = decode.read_varint()?;
assert_eq!(value, 300);

Highlights

Tips

Part of the COOLJAPAN ecosystem

OxiProto is part of NoFFI — the COOLJAPAN initiative to replace every C/C++/Fortran/-sys FFI dependency in the Rust ecosystem with a clean, memory-safe, 100% Pure Rust implementation. Here the target is protoc: the C++ protobuf compiler, plus the protoc invocations baked into prost-build and tonic-build. Default features are 100% Pure Rust — no C, C++, or Fortran in the default set, and no protobuf-compiler system package needed.

Within the ecosystem, OxiProto depends on nothing else and sits at the bottom of the stack: it’s the foundation for OxiRPC (gRPC) and any future crate that speaks the protobuf wire format. It sits alongside the broader oxi* family across the sovereign Rust stack.

Repository: https://github.com/cool-japan/oxiproto

Star the repo if you want a protobuf toolchain that builds anywhere Rust does. 🦀

Pure Rust serialization — sovereign, safe, and FFI-free.

KitaSan at COOLJAPAN OÜ June 20, 2026

↑ Back to all posts