Thanks to visit codestin.com
Credit goes to lib.rs

#cross-platform #config-dir #xdg #directory

dir_spec

A cross-platform Rust library for resolving XDG and platform-specific directories with proper fallbacks

8 releases (5 breaking)

Uses new Rust 2024

0.5.2 Apr 11, 2026
0.5.1 Apr 10, 2026
0.5.0 Aug 29, 2025
0.4.0 Aug 28, 2025
0.0.1 Aug 8, 2025

#241 in Filesystem

Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App

557 downloads per month
Used in 10 crates (5 directly)

MIT license

64KB
1K SLoC

dir_spec

Crates.io Build Documentation Codacy grade License: MIT

A cross-platform Rust library for resolving XDG and platform-specific directories with proper fallbacks.

Why Another Directory Library?

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.

Features

  • 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 std library
  • Type-safe: Returns Option<PathBuf> for simple error handling

Usage

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());
  }
}

Supported Directories

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 $TMPDIR or /tmp $TMPDIR or /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:

  1. Same as the corresponding *_home() function on non-Windows platforms
  2. Returns None on Windows as there is no standard user fonts directory

Directory Types Explained

Config vs. Config Local

  • config_home(): Roaming config directory (synced across machines on Windows)
  • config_local(): Local config directory (machine-specific, not synced)

Data vs. Data Local

  • data_home(): Roaming data directory (synced across machines on Windows)
  • data_local(): Local data directory (machine-specific, not synced)

Config vs. Preferences

  • config_home(): General application configuration
  • preferences(): Platform-specific preferences (macOS: .plist files via Apple APIs)

Fonts

  • fonts(): User-installed fonts directory
  • Returns None on Windows as there's no standard user fonts directory

XDG Environment Variable Priority

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.

Cross-Platform Behavior

Linux

Follows XDG Base Directory Specification defaults when XDG variables aren't set.

macOS

  • Respects XDG variables if set (common among CLI tool users)
  • Falls back to native macOS locations (~/Library/Application Support, etc.)
  • Uses ~/Movies for videos (not ~/Videos)
  • preferences() points to ~/Library/Preferences for .plist files

Windows

  • 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)

Error Handling

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")
});

Dependencies

None! This crate only uses Rust's standard library.

License

Licensed under the MIT LICENSE

Contributing

Contributions are welcome! Please ensure:

  1. All platforms are tested
  2. XDG compliance is maintained
  3. Platform-specific fallbacks follow native conventions
  4. New methods include appropriate documentation

References

No runtime deps