JSON Config File to Rust Struct

Generate a strongly-typed Rust config struct from a JSON config file. Covers defaults, validation, and merging with environment variables.

Real-World

Detailed Explanation

Loading a JSON Config File into a Typed Struct

Many CLI tools and services load runtime configuration from a JSON file. Converting that file's structure into a Rust struct gives you compile-time validation of every key and free defaults via serde.

Example config file

{
  "server": {
    "host": "0.0.0.0",
    "port": 8080,
    "workers": 4
  },
  "database": {
    "url": "postgres://localhost/myapp",
    "pool_size": 10,
    "timeout_seconds": 30
  },
  "logging": {
    "level": "info",
    "format": "json"
  },
  "features": {
    "experimental_search": false,
    "rate_limiting": true
  }
}

Generated Rust

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppConfig {
    pub server: Server,
    pub database: Database,
    pub logging: Logging,
    pub features: Features,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Server {
    pub host: String,
    pub port: i32,
    pub workers: i32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Database {
    pub url: String,
    pub pool_size: i32,
    pub timeout_seconds: i32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Logging {
    pub level: String,
    pub format: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Features {
    pub experimental_search: bool,
    pub rate_limiting: bool,
}

Adding defaults

For an optional file or partial config, wrap the struct in #[serde(default)]:

impl Default for Server {
    fn default() -> Self {
        Self {
            host: "127.0.0.1".into(),
            port: 8080,
            workers: 1,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct AppConfig {
    #[serde(default)]
    pub server: Server,
    // ...
}

Now missing sections fall back to the Default implementation rather than failing.

Loading the file

let raw = std::fs::read_to_string("config.json")?;
let config: AppConfig = serde_json::from_str(&raw)?;

Promoting strings to enums

logging.level is a perfect candidate for an enum (Trace, Debug, Info, Warn, Error). After generating the initial struct, follow the enum-from-string recipe to lock down the valid values.

Use Case

Web servers, CLI tools, embedded systems, and game engines all benefit from typed config parsing. A typo in the config file becomes a clear deserialization error rather than a silent runtime bug.

Try It — JSON to Rust Struct Converter

Open full tool