A cross-platform Rust library for resolving XDG and platform-specific directories with proper fallbacks.
Most existing directory libraries (like dirs) ignore XDG environment variables on macOS and Windows, defaulting to
platform-specific locations even when users have explicitly set XDG variables. This crate prioritizes XDG compliance
across all platforms while providing sensible platform-specific fallbacks.
- XDG-first approach: Respects XDG environment variables on all platforms
- Platform-aware fallbacks: Uses native conventions when XDG variables aren't set
- Cross-platform: Works on Linux, macOS, and Windows
- Zero dependencies: Only uses stdlibrary
- Type-safe: Returns Option<PathBuf>for simple error handling
Add this to your Cargo.toml:
[dependencies]
dir_spec = "0.5.0"Basic usage:
fn main() {
  // Get config directory (respects XDG_CONFIG_HOME if set)
  if let Some(config_dir) = dir_spec::config_home() {
    println!("Config: {}", config_dir.display());
  }
  // Get cache directory (respects XDG_CACHE_HOME if set)
  if let Some(cache_dir) = dir_spec::cache_home() {
    println!("Cache: {}", cache_dir.display());
  }
  // Get user's home directory
  if let Some(home_dir) = dir_spec::home() {
    println!("Home: {}", home_dir.display());
  }
}| Method | XDG Variable | Linux Default | macOS Default | Windows Default | 
|---|---|---|---|---|
| bin_home() | XDG_BIN_HOME | ~/.local/bin | ~/.local/bin | %LOCALAPPDATA%\Programs | 
| cache_home() | XDG_CACHE_HOME | ~/.cache | ~/Library/Caches | %LOCALAPPDATA% | 
| config_home() | XDG_CONFIG_HOME | ~/.config | ~/Library/Application Support | %APPDATA% | 
| config_local() | — | ~/.config¹ | ~/Library/Application Support¹ | %LOCALAPPDATA% | 
| data_home() | XDG_DATA_HOME | ~/.local/share | ~/Library/Application Support | %APPDATA% | 
| data_local() | — | ~/.local/share¹ | ~/Library/Application Support¹ | %LOCALAPPDATA% | 
| desktop() | XDG_DESKTOP_DIR | ~/Desktop | ~/Desktop | %USERPROFILE%\Desktop | 
| documents() | XDG_DOCUMENTS_DIR | ~/Documents | ~/Documents | %USERPROFILE%\Documents | 
| downloads() | XDG_DOWNLOAD_DIR | ~/Downloads | ~/Downloads | %USERPROFILE%\Downloads | 
| fonts() | — | ~/.local/share/fonts | ~/Library/Fonts | None² | 
| home() | HOME/USERPROFILE | $HOME | $HOME | %USERPROFILE% | 
| music() | XDG_MUSIC_DIR | ~/Music | ~/Music | %USERPROFILE%\Music | 
| pictures() | XDG_PICTURES_DIR | ~/Pictures | ~/Pictures | %USERPROFILE%\Pictures | 
| preferences() | — | ~/.config¹ | ~/Library/Preferences | %APPDATA%¹ | 
| publicshare() | XDG_PUBLICSHARE_DIR | ~/Public | ~/Public | C:\Users\Public | 
| runtime() | XDG_RUNTIME_DIR | $TMPDIRor/tmp | $TMPDIRor/tmp | %TEMP% | 
| state_home() | XDG_STATE_HOME | ~/.local/state | ~/Library/Application Support | %LOCALAPPDATA% | 
| templates() | XDG_TEMPLATES_DIR | ~/Templates | ~/Templates | %USERPROFILE%\Templates | 
| videos() | XDG_VIDEOS_DIR | ~/Videos | ~/Movies | %USERPROFILE%\Videos | 
Notes:
- Same as the corresponding *_home()function on non-Windows platforms
- Returns Noneon Windows as there is no standard user fonts directory
- config_home(): Roaming config directory (synced across machines on Windows)
- config_local(): Local config directory (machine-specific, not synced)
- data_home(): Roaming data directory (synced across machines on Windows)
- data_local(): Local data directory (machine-specific, not synced)
- config_home(): General application configuration
- preferences(): Platform-specific preferences (macOS:- .plistfiles via Apple APIs)
- fonts(): User-installed fonts directory
- Returns Noneon Windows as there's no standard user fonts directory
This crate always checks XDG environment variables first, regardless of platform:
// This will use XDG_CONFIG_HOME if set, even on macOS/Windows
export XDG_CONFIG_HOME="/custom/config/path"
let config = dir_spec::config_home(); // Returns Some("/custom/config/path")If XDG variables aren't set, the crate falls back to platform-appropriate defaults.
Follows XDG Base Directory Specification defaults when XDG variables aren't set.
- Respects XDG variables if set (common among CLI tool users)
- Falls back to native macOS locations (~/Library/Application Support, etc.)
- Uses ~/Moviesfor videos (not~/Videos)
- preferences()points to- ~/Library/Preferencesfor- .plistfiles
- Respects XDG variables if set
- Falls back to Windows conventions (%APPDATA%,%LOCALAPPDATA%, etc.)
- Public directory points to system-wide C:\Users\Public
- config_local()and- data_local()use- %LOCALAPPDATA%for non-roaming storage
- fonts()returns- None(no standard user fonts directory)
All methods return Option<PathBuf>. Methods return None when:
- Home directory cannot be determined
- Required environment variables are missing (Windows-specific cases)
- Platform-specific directory resolution fails
- Directory doesn't exist on the platform (e.g., fonts()on Windows)
match dir_spec::config_home() {
    Some(path) => println!("Config dir: {}", path.display()),
    None => eprintln!("Failed to get config dir"),
}
// Or using if-let
if let Some(config_path) = dir_spec::config_home() {
    println!("Config dir: {}", config_path.display());
}
// For fallback handling
let config_dir = dir_spec::config_home().unwrap_or_else(|| {
    // Fallback to current directory or panic, depending on your needs
    std::env::current_dir().expect("Cannot determine current directory")
});None! This crate only uses Rust's standard library.
Licensed under the MIT LICENSE
Contributions are welcome! Please ensure:
- All platforms are tested
- XDG compliance is maintained
- Platform-specific fallbacks follow native conventions
- New methods include appropriate documentation