Path API

Learn how to access standard system directories and manipulate file paths using the Tauri v2 Path API from your React frontend.

The Path API removes the guesswork from locating standard directories like Documents, AppData, or the user’s home folder. Without it, you’d have to write platform‑specific logic for Windows, macOS, and Linux just to find where your app’s config file should live. The API gives you a consistent, cross‑platform set of functions that return the correct paths for the current operating system, and it provides helper utilities to join, resolve, and inspect paths safely — avoiding the dreaded double‑slash or wrong‑separator bugs.

All Path API functions live under the path namespace of @tauri-apps/api. You import them once and use them directly from your React components or service code, just like any other JavaScript module. The Introduction covers why this module exists and how it differs from the File System API.

Permission Requirements

The Path API is part of Tauri’s core and does not require a separate plugin, but you still need to grant the appropriate capability.

Add "path:default" to the permissions list in your capability file (for example src-tauri/capabilities/default.json). The default permission allows all path functions. For tighter control, you can pick individual permissions like "path:allow-app-dir", but for learning the API, the default set is the easiest starting point.

src-tauri/capabilities/default.json
{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "default",
  "description": "Capability for the main window",
  "windows": ["main"],
  "permissions": [
    "core:default",
    "path:default"
  ]
}

Missing permission leads to silent failures:

If you call a path function without the right permission, Tauri will reject the promise with an error like "path:default not allowed". The error is thrown asynchronously, so always await the call or handle .catch() — otherwise your app may silently stop working at that point.

System Directories

Every operating system has its own convention for where to store user files, application data, caches, and media. The Path API exposes these system directories through a set of async functions, each returning a string path specific to the current platform. Internally, Tauri uses the Rust dirs crate to resolve these directories, so the paths are always the ones the OS recommends, not custom guesses.

The functions are grouped into two categories: user‑centric directories (Documents, Desktop, Downloads, etc.) and application‑centric directories (app config, app data, cache). Knowing which to use for a given file is the difference between an app that feels native and one that dumps everything in the wrong folder.

Common user directories

These point to well‑known folders that belong to the current user.

import { path } from "@tauri-apps/api";
const home = await path.homeDir();
const docs = await path.documentDir();
const dl = await path.downloadDir();
const desktop = await path.desktopDir();
const pics = await path.pictureDir();
const vids = await path.videoDir();
const audio = await path.audioDir();

Each function returns a string like C:\Users\Alice\Documents on Windows, /Users/Alice/Documents on macOS, or /home/alice on Linux. They are all async — you must await them inside an async context. If you call them at the top level of a module, wrap the logic in an async function.

These directories are not guaranteed to exist:

The API returns the suggested path according to the OS standard, but it does not create the folder. If the user has a non‑standard setup or the directory has been manually deleted, you may get a path to a location that doesn’t exist yet. Always check existence (with the File System API) before writing, or create it yourself.

Application‑specific directories

When your app needs to store persistent data — like configuration, logs, or database files — these are the directories you should use instead of cluttering the user’s Documents.

const appData = await path.appDataDir();
const appConfig = await path.appConfigDir();
const appCache = await path.cacheDir();
const appLocalData = await path.appLocalDataDir();
  • appDataDir() → cross‑platform application data folder (e.g., %APPDATA%/com.myapp on Windows, ~/Library/Application Support/com.myapp on macOS, ~/.local/share/com.myapp on Linux).
  • appConfigDir() → app config folder, often the same as appDataDir() on some platforms but meant strictly for configuration.
  • appCacheDir() → ephemeral cache that the OS may purge under disk pressure.
  • appLocalDataDir() → similar to appDataDir() but for data that should not be roamed with the user profile on Windows.

These folders are scoped to your Tauri bundle identifier (the identifier field in tauri.conf.json). That means two different Tauri apps will never accidentally read each other’s data.

Resource directory

For files bundled alongside your application — like compiled assets, templates, or images that ship with the installer — use resourceDir().

const resources = await path.resourceDir();

On Windows this returns the directory containing the .exe file. On macOS it points inside the .app bundle (MyApp.app/Contents/Resources). On Linux it’s the directory alongside the binary.

Do not write to the resource directory:

The resource directory is read‑only in many deployment scenarios (sandboxed macOS apps, Flatpak, or when the app is installed system‑wide). Attempting to create or modify files there will cause permission errors. For mutable data, always use the app‑specific directories above.

Other specialized directories

The API also exposes directories for fonts, public shared files, runtime sockets, and templates. You’ll rarely need them day‑to‑day, but they are available when you do.

const fonts = await path.fontDir();
const publicDir = await path.publicDir();
const runtime = await path.runtimeDir();
const templates = await path.templateDir();
  • fontDir() — system fonts folder (platform‑specific).
  • publicDir() — shared public directory (e.g., C:\Users\Public on Windows).
  • runtimeDir() — often used for Unix domain sockets or IPC endpoints.
  • templateDir() — templates folder (e.g., for new document templates).

If you see a correct path logged, your permission setup is working:

A quick sanity check: call console.log(await path.homeDir()) in your React app after setting up permissions. If a valid‑looking path appears in the console, the capability is configured correctly.

Working with Paths

Knowing where a directory is located is only half the story. Real applications need to join path segments, resolve relative references, normalize inconsistent separators, and extract file extensions. The Path API provides a set of utilities that mirror what Node.js’s path module does — but they work on any platform, automatically adapting to the OS.

Joining paths with join()

Never concatenate paths with string addition. On Windows the separator is \, on Linux and macOS it’s /. Hard‑coding one will break the app when running on the other. Use join() to combine segments safely.

import { path } from "@tauri-apps/api";
const configDir = await path.appConfigDir();
const configPath = await path.join(configDir, "settings.json");
console.log(configPath);
// On Windows:  C:\Users\Alice\AppData\Roaming\com.myapp\config\settings.json
// On macOS:    /Users/Alice/Library/Application Support/com.myapp/config/settings.json

join() takes any number of segments and returns a normalized path with the correct separator for the current platform. It also removes redundant separators and resolves .. sequences.

Don't prepend separators on segments:

A common mistake is passing segments like "/settings.json" to join(). This treats the second segment as an absolute path and effectively discards the first part. Pass plain names without leading slashes.

Resolving paths relative to a base directory with resolvePath()

When you have a user‑provided filename or a relative path, you can anchor it to a known system directory using resolvePath(). It takes a relative path (string or array of segments) and a base directory from the BaseDirectory enum, then returns the full absolute path.

import { path, BaseDirectory } from "@tauri-apps/api";
// Resolve "logs/app.log" inside the app data directory
const logPath = await path.resolvePath("logs/app.log", BaseDirectory.AppData);
console.log(logPath);

BaseDirectory is an enum that maps directly to the functions we saw earlier. Common variants include AppData, AppConfig, Cache, Home, Resource, Desktop, and others. This approach keeps the directory selection logic centralized and ensures the path is always rooted in the right place.

You can also pass an array of segments:

const configPath = await path.resolvePath(
  ["config", "user.json"],
  BaseDirectory.AppConfig
);

resolvePath() is especially useful when your frontend doesn’t need to know the full absolute path — it just knows the logical location (like “store this under AppData” ) and works with a relative path. It also handles path traversal internally, so passing "../../secret" won’t escape the base directory sandbox.

Extracting parts of a path

The API includes helpers that let you decompose a path into its components without trying to split strings yourself.

const fullPath = await path.join(
  await path.appConfigDir(),
  "data/backups/2024.zip"
);
const dir = await path.dirname(fullPath);   // parent directory
const file = await path.basename(fullPath); // "2024.zip"
const ext = await path.extname(fullPath);   // ".zip"
  • dirname() returns everything before the last separator.
  • basename() returns the last component (filename with extension).
  • extname() returns the extension including the dot, or an empty string if there is none.

These are pure string operations; they don’t require the file to exist. They are also platform‑aware, so extname("archive.tar.gz") returns ".gz", not ".tar.gz".

Normalizing and testing paths

Two more utilities cover common validation needs.

const messy = await path.normalize("config/../data/./log.txt");
console.log(messy); // "data/log.txt"
const absolute = await path.isAbsolute("/usr/local/bin");
console.log(absolute); // true (on Linux/macOS)

normalize() collapses .. and . segments and converts separators to the platform default. isAbsolute() returns true if the path starts from the root (like / on Unix or C:\ on Windows), false if it’s relative.

Platform‑specific separator

Hard‑coding / or \ might still be necessary when you build paths manually (for display purposes, not for filesystem access). The API exports sep for this.

import { path } from "@tauri-apps/api";
console.log(path.sep); // "/" on macOS/Linux, "\" on Windows

Use it sparingly — join() should be your go‑to for building real filesystem paths.

A practical workflow from start to finish

The steps below illustrate a complete read‑config‑file flow that ties system directories and path manipulation together.

1

Get the app configuration directory

const configDir = await path.appConfigDir();

This is the folder scoped to your app’s bundle identifier, the safe place for settings.

2

Join with the filename

const configFile = await path.join(configDir, "app-settings.json");

The join call handles any missing or extra separators automatically.

3

Read the file content (optional)

With a valid path, you can use Tauri’s File System API to read the file:

import { fs } from "@tauri-apps/api";
const content = await fs.readTextFile(configFile);

This step requires the "fs:default" capability, but it demonstrates how the Path API feeds into other I/O operations.

Everything wires together correctly:

If the console shows the full path and the file read succeeds, you’ve confirmed that the permission model, the path resolution, and the I/O layer all cooperate as intended. This is the sign of a properly wired Tauri app.


The Path API is rarely the star of the show, but it’s the invisible scaffolding that prevents an app from littering the user’s filesystem or breaking on a different platform. When you combine the directory functions with the path manipulation utilities, you can treat file locations as logical concepts — “app config” or “downloads folder” — rather than as brittle string concatenation.

Introduction to the Path API

Understand what the Tauri Path API is, why it exists, and how it helps you locate system and application directories in a cross-platform desktop application.

System Directories

Learn how Tauri v2 system base directories map to real file system locations and how to use them to read, write, and manage files in a cross-platform desktop app.

Working with Paths in Tauri v2

Learn to join, resolve, normalize, and extract parts of file paths safely across platforms using the Tauri v2 Path API from a React frontend.