| Crates.io | fs-embed |
| lib.rs | fs-embed |
| version | 0.2.4 |
| created_at | 2025-07-18 13:13:01.174821+00 |
| updated_at | 2025-07-30 02:51:12.191479+00 |
| description | Embed files in release, read from disk in debug — with a unified API. |
| homepage | https://github.com/vivsh/fs-embed |
| repository | https://github.com/vivsh/fs-embed |
| max_upload_size | |
| id | 1758942 |
| size | 38,046 |
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.
fs_embed!()DirSetuse 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}");
}
}
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");
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() — Returns true if directory is embeddedDir::into_dynamic() — Always use disk (dynamic) modeDir::auto_dynamic() — Use disk in debug, embedded in releaseFile::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)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
}
walk_override()This crate includes comprehensive tests for all public API. To run tests:
cargo test -p fs-embed
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.
rust-silosIf 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.