Object Serialization in Rust: serde, bincode, JSON and YAML

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Object Serialization in Rust: Complete Guide to the serde Library and Data Formats



Serialization is the process of converting data structures or objects into a format that can be saved to a file, transmitted over a network, or cached. In the Rust language, this task is solved elegantly and efficiently using the serde library (Serialization/Deserialization). In this article, we will take a detailed look at how serialization works in Rust, which data formats are supported, and how to choose the right tool for your project.



What is serde and why is it the de facto standard?



serde is a framework for serializing and deserializing data structures in Rust. It is not tied to a specific format — you can use JSON, Bincode, YAML, TOML, MessagePack, CBOR, and many others. The main idea: you describe your structure once, and serde automatically generates code for working with any format through the Serialize and Deserialize trait system.



Advantages of serde:

  • Maximum performance — code is generated at compile time (zero-cost abstraction)
  • Type safety — format mismatch errors are caught at compile time
  • Support for complex structures: enums, vectors, hash maps, nested objects
  • Customization through attributes


Installation and basic setup



Add the following dependencies to Cargo.toml:



[dependencies]serde = { version = "1.0", features = ["derive"] }serde_json = "1.0"bincode = "1.3"


The key point is the "derive" feature for serde. Without it, you would have to manually implement the Serialize and Deserialize traits.



Simple example: serialization to JSON



JSON is the most popular format for web applications and APIs. Let's look at a basic example:



use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]struct User { id: u32, name: String, email: String, is_active: bool,}

fn main() { let user = User { id: 42, name: "Alexey".to_string(), email: "alex@example.com".to_string(), is_active: true, };

// Serialization to JSON let json = serde_json::to_string(&user).unwrap(); println!("JSON: {}", json);

// Deserialization from JSON let deserialized: User = serde_json::from_str(&json).unwrap(); println!("Deserialized: {:?}", deserialized);}


Output:

JSON: {"id":42,"name":"Alexey","email":"alex@example.com","is_active":true}Deserialized: User { id: 42, name: "Alexey", email: "alex@example.com", is_active: true }


Binary serialization with bincode



For high-performance applications (games, real-time systems, databases), a compact binary format is often required. bincode is one of the best options:



use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]struct GameState { level: u16, health: f32, inventory: Vec<String>, checkpoint: (f64, f64),}

fn main() { let state = GameState { level: 5, health: 87.5, inventory: vec!["sword".into(), "potion".into()], checkpoint: (120.5, -34.8), };

// Serialization to binary format let binary = bincode::serialize(&state).unwrap(); println!("Binary size: {} bytes", binary.len());

// Deserialization let restored: GameState = bincode::deserialize(&binary).unwrap(); println!("Restored: {:?}", restored);}


Bincode provides gains in data size and processing speed compared to JSON. For example, a structure with 4 fields will take about 40 bytes versus 100+ in JSON.



Working with YAML and TOML



For configuration files

Recommendations