4 releases
Uses new Rust 2024
| 0.2.4 | Jul 30, 2025 |
|---|---|
| 0.2.2 | Jul 19, 2025 |
| 0.2.1 | Jul 19, 2025 |
| 0.1.0 | Jul 18, 2025 |
#454 in Embedded development
177 downloads per month
26KB
445 lines
fs-embed
Embed directories into your binary at compile time, or read from disk at runtime, with a unified and ergonomic API. Supports overlays, dynamic mode, and directory composition.
Features
- Embed directories or files at compile time using a single macro:
fs_embed!() - Switch between embedded and disk-backed (dynamic) mode at runtime
- Compose multiple directories with overlays using
DirSet - Access files and subdirectories by path, list entries, and walk recursively
- Overlay/override support: later directories take precedence
- No build scripts, no config, no env vars
- Robust error handling and path normalization
Example Usage
use fs_embed::fs_embed;
// Embed the "static" folder
static STATIC: fs_embed::Dir = fs_embed!("static");
fn main() {
// Use disk in debug, embedded in release
let dir = STATIC.auto_dynamic();
if let Some(file) = dir.get_file("css/style.css") {
let content = file.read_str().unwrap();
println!("{content}");
}
}
Macro Usage and Options
The fs_embed! macro expects a literal relative path inside your crate, resolved via CARGO_MANIFEST_DIR.
static DIR: fs_embed::Dir = fs_embed!("assets");
By default, in debug mode, files are read from disk for hot-reload; in release mode, files are embedded in the binary.
Example with options:
static DIR: fs_embed::Dir = fs_embed!("assets");
Directory API
Dir
Dir::get_file(path)— Get a file by relative pathDir::get_dir(path)— Get a subdirectory by relative pathDir::entries()— List all immediate entries (files and subdirectories)Dir::walk()— Recursively yield all filesDir::is_embedded()— Returnstrueif directory is embeddedDir::into_dynamic()— Always use disk (dynamic) modeDir::auto_dynamic()— Use disk in debug, embedded in release
File
File::file_name()— Get the file nameFile::extension()— Get the file extensionFile::read_bytes()— Read file contents as bytesFile::read_str()— Read file contents as UTF-8 stringFile::metadata()— Get file metadata (size, modified time)
DirSet (Overlays)
You can compose multiple directories using DirSet to support overlays and override semantics. Later directories in the set override files from earlier ones with the same relative path.
use fs_embed::{fs_embed, DirSet};
static BASE: fs_embed::Dir = fs_embed!("base");
static THEME: fs_embed::Dir = fs_embed!("theme");
let set = DirSet::new(vec![BASE, THEME]);
if let Some(file) = set.get_file("index.html") {
// File from THEME if it exists, otherwise BASE
}
- Overlay precedence is left-to-right
- Only the highest-precedence file for each path is returned by
walk_override()
Tests
This crate includes comprehensive tests for all public API. To run tests:
cargo test -p fs-embed
License
This crate is dual-licensed under either the MIT or Apache-2.0 license, at your option. See LICENSE-MIT and LICENSE-APACHE for details.
Related Crate: rust-silos
If you only need to embed files and access them by path (without directory traversal, overlays, or virtual filesystem features), consider using rust-silos. It provides a minimal, highly efficient, and allocation-free API for file embedding, ideal for simple use cases where directory APIs are not required.
Links
Dependencies
~2.2–7MB
~152K SLoC