Postcard for Rust: Compact Serde Serialization in no_std Systems
A no_std + serde compatible message library for Rust
At a glance
- What is it?
- Postcard is a no_std-focused serializer and deserializer for Serde, aimed at embedded and other constrained Rust environments. Its main trade-off is a compact binary format with documented cautions around unsupported Serde attributes.
- Who is it for?
- Adopt Postcard when an embedded or otherwise constrained Rust system needs Serde serialization with a documented stable format and `no_std` support. Do not choose it without checking whether your data model uses `serde(flatten)`, `skip_serializing_if`, or unusual `skip` placement, because the README identifies failure and silent-mismatch risks.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Postcard solves for constrained Rust
Postcard is a serializer and deserializer for Serde with a primary focus on `#![no_std]` programs. The README identifies embedded systems and other constrained environments as its main target, so the library is aimed at developers choosing a binary message format rather than developers seeking a human-readable configuration format. Its stated goals include minimizing memory usage first, followed by code size, developer time, and CPU time.
The library is designed to keep communication code similar between microcontrollers and desktop or server programs. That matters when a message type is shared across constrained devices and larger systems: the serialization interface can remain based on Serde rather than changing to a device-specific encoding API. Postcard also aims to support a broad set of Serde features, allowing it to serve as a Serde format replacement for suitable message types.
This is a focused library rather than a complete networking stack. The documented example serializes a borrowed byte slice and string, then deserializes the same value from the resulting buffer. It does not define transports, retries, framing, acknowledgements, or application-level message schemas.
Postcard wire format and serialization mechanics
Postcard uses a compact binary representation. According to the README, signed and unsigned integers larger than eight bits are encoded with a Varint. The same encoding is used for array slice lengths and enum discriminants. This design reduces the number of bytes needed for values whose values are small, although the README does not provide compression information or universal size guarantees.
The format is not presented as a casual implementation detail. The README states that, as of `v1.0.0`, Postcard has a documented and stable wire format, with the specification stored in the repository's `spec/` folder and published at `https://postcard.jamesmunns.com`. That makes the encoding a protocol boundary worth reviewing before deploying multiple devices or services that must interoperate.
The library also has a Flavors system. The README describes flavors as plugins or middleware used during serialization and deserialization. They can be combined to obtain protocol formats with different processing behavior. The repository layout includes separate source crates such as `postcard-core`, `postcard-derive`, `postcard-dyn`, `postcard-schema`, and related packages, but the README does not document the complete configuration surface of every flavor.
Installing Postcard and completing a first message
The README's setup instructions use the `postcard` version `1.1` and add the `no-std` subset of `serde` by disabling its default features. This configuration is appropriate for a Rust target that cannot depend on the standard library. Add the dependencies to the `[dependencies]` section of the application's `Cargo.toml`.
[dependencies]
postcard = "1.1"
serde = { version = "1.0", default-features = false }The first example serializes a borrowed message into a fixed-capacity `heapless::Vec<u8>`. The `to_vec` call returns a result, so the application must handle allocation or capacity failure rather than assuming that serialization always succeeds.
use core::ops::Deref;
use serde::{Serialize, Deserialize};
use postcard::{from_bytes, to_vec};
use heapless::Vec;
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct RefStruct<'a> {
bytes: &'a [u8],
str_s: &'a str,
}
let message = "hElLo";
let bytes = [0x01, 0x10, 0x02, 0x20];
let output: Vec<u8, 11> = to_vec(&RefStruct {
bytes: &bytes,
str_s: message,
}).unwrap();The README then deserializes the buffer with `from_bytes` and compares the result with the original value.
let out: RefStruct = from_bytes(output.deref()).unwrap();
assert_eq!(
out,
RefStruct {
bytes: &bytes,
str_s: message,
}
);The alternative `alloc` feature uses `to_allocvec` and an `alloc::vec::Vec<u8>`. The README includes this as an optional allocation-backed path, while the default `heapless` feature is the more direct example for constrained targets.
Feature choices and the heapless versus alloc boundary
Postcard offers at least two output paths in the documented examples. `heapless` writes into a fixed-capacity vector, which avoids a conventional heap allocation but requires the caller to choose and enforce a capacity. `alloc` writes into an allocating vector through `to_allocvec`, which is more convenient where an allocator is available but is not equivalent to a no-allocation design.
That distinction affects application code beyond the serializer call. A fixed capacity can produce an error when a message does not fit, while an allocating vector can grow but requires the target to provide `alloc`. The README does not document retry, partial-write, or streaming behavior for the `heapless` example, so applications should not infer those semantics from the example.
The workspace also contains `postcard2` and `postcard2-heapless`, as shown in the top-level `Cargo.toml`. The README focuses on the `postcard = "1.1"` package and does not explain whether adopters should use that package or the later workspace crates for a new design. That package-selection question needs checking against the project's current crate documentation before implementation.
Serde attributes that can break a message format
Postcard's Serde integration has explicit hazards, and the README does not treat attributes as universally interchangeable. It recommends extensive testing when `serde` attributes are used because several attributes can cause serialization or deserialization problems.
The README specifically lists `serde(flatten)` and `serde(skip_serializing_if($COND))` as attributes that break serialization or deserialization in some cases. It also warns about `serde(skip)`. For enum variants, skipped fields must be the last variants; otherwise Postcard may deserialize against an offset discriminant, causing a failure or a silent mismatch on C-like enums. This is a protocol correctness issue, not merely a style concern, because a value can be decoded into the wrong shape without an immediate error.
A practical schema review should therefore identify every Serde attribute used by the message types, then confirm round trips with both serialization and deserialization. The README does not provide a complete compatibility matrix for all Serde attributes, so its tracking issue for this behavior is the relevant place to investigate before relying on an attribute-heavy schema.
Where Postcard is the wrong format
Postcard is a poor fit when a human-readable or directly editable representation is required, because its documented examples produce binary bytes and the README describes Varint encoding rather than a text syntax. It is also a poor fit when the protocol must be consumed by systems that do not implement the Postcard specification.
The compact binary format can make debugging less direct. The README provides a fixed byte assertion, which is useful for tests, but it does not document a general inspection command, logging format, or schema browser. Engineers should not assume that `from_bytes` failure always identifies the offending field. The README gives no such diagnostic guarantee.
A conventional Serde format with a self-describing textual representation may be easier for command-line tools, manual inspection, or interoperability with systems optimized for JSON or another established encoding. Postcard is more relevant when both ends share Rust types and the design priority is constrained execution. Flavors can alter processing, but the README does not establish that they eliminate interoperability or inspectability concerns.
Alternatives, licensing, and maintenance
A real alternative is a conventional Serde text format such as a JSON-oriented Serde implementation. The difference is approach: a text format prioritizes readable, externally inspectable data, while Postcard uses a compact binary format and Varints, with the README explicitly prioritizing constrained-resource use. The alternative may require more bytes and may have different parsing costs, but it can be easier to inspect outside Rust.
Postcard is licensed under either the Apache License, Version 2.0 or the MIT license, at the user's option. The repository includes `LICENSE-APACHE` and `LICENSE-MIT`. Contributions are described as dual licensed under the same terms unless contributors state otherwise. That is a licensing choice to account for in an adoption review, not a technical recommendation from this article.
The repository is not archived. Its last push was on 2026-09-21, which is within the six-month period used for maintenance classification. The release list includes `postcard2/v0.2.0` from 2025-12-27, `postcard-schema/v0.2.5` from 2025-08-23, and `postcard-schema-ng/v0.3.2` from 2025-08-23. The README does not provide upgrade procedures or a compatibility policy for moving between these packages, so version selection should be checked against the exact crate being adopted.
Editorial conclusion
Adopt Postcard when an embedded or otherwise constrained Rust system needs Serde serialization with a documented stable format and `no_std` support. Do not choose it without checking whether your data model uses `serde(flatten)`, `skip_serializing_if`, or unusual `skip` placement, because the README identifies failure and silent-mismatch risks. Verify feature selection, target compatibility, and the exact behavior of every Serde attribute before committing a protocol to it.
Frequently asked questions
How do I install Postcard for a Rust no_std project?
Add `postcard = "1.1"` and configure Serde with `default-features = false` in the project's `[dependencies]` section. The README specifically warns that Serde's default `std` feature is unsuitable for embedded targets.
Does Postcard allocate memory when serializing?
The README documents a default `heapless` example using `heapless::Vec<u8>` with a fixed capacity, and an optional `alloc` example using `to_allocvec` with `alloc::vec::Vec<u8>`. The available output path depends on the selected feature and target environment.
Which Serde attributes should I avoid with Postcard?
The README calls out `serde(flatten)` and `serde(skip_serializing_if($COND))` as attributes that can break serialization or deserialization. It also warns that `serde(skip)` can cause enum deserialization failures or silent mismatches when skipped fields are not the last variants.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jamesmunns-postcard)Was this useful?