> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/sxyazi/yazi/llms.txt
> Use this file to discover all available pages before exploring further.

# Filesystem API

> Filesystem operations in Yazi plugins

The `fs` namespace provides filesystem operations that work with both local and remote (VFS) files.

## File Access

### `fs.access()`

Create a file access builder for opening files with specific permissions.

<ResponseField name="return" type="Access">
  Access builder object
</ResponseField>

```lua theme={null}
local access = fs.access()
  :read(true)
  :write(true)
  
local fd, err = access:open(url)
if fd then
  -- Use file descriptor
  ya.drop(fd)
end
```

#### Access Methods

* **`:append(bool)`** - Open for appending
* **`:create(bool)`** - Create file if it doesn't exist
* **`:create_new(bool)`** - Create new file, fail if exists
* **`:read(bool)`** - Open for reading
* **`:write(bool)`** - Open for writing
* **`:truncate(bool)`** - Truncate file on open
* **`:open(url)`** - Open the file and return file descriptor

## File Operations

### `fs.copy(from, to)`

Copy a file from one location to another.

<ParamField path="from" type="Url" required>
  Source file URL
</ParamField>

<ParamField path="to" type="Url" required>
  Destination file URL
</ParamField>

<ResponseField name="return" type="number|nil, Error">
  Number of bytes copied, or (nil, error)
</ResponseField>

```lua theme={null}
local len, err = fs.copy(src_url, dest_url)
if not len then
  ya.err("Copy failed: " .. tostring(err))
end
```

### `fs.rename(from, to)`

Rename/move a file or directory.

<ParamField path="from" type="Url" required>
  Source URL
</ParamField>

<ParamField path="to" type="Url" required>
  Destination URL
</ParamField>

<ResponseField name="return" type="bool, Error|nil">
  Success boolean, or (false, error)
</ResponseField>

```lua theme={null}
local ok, err = fs.rename(old_url, new_url)
if not ok then
  ya.err("Rename failed: " .. tostring(err))
end
```

### `fs.write(url, data)`

Write data to a file.

<ParamField path="url" type="Url" required>
  File URL
</ParamField>

<ParamField path="data" type="string" required>
  Data to write
</ParamField>

<ResponseField name="return" type="bool, Error|nil">
  Success boolean, or (false, error)
</ResponseField>

```lua theme={null}
local ok, err = fs.write(url, "Hello, World!")
```

## Directory Operations

### `fs.create(type, url)`

Create a directory.

<ParamField path="type" type="string" required>
  Either `"dir"` or `"dir_all"` (creates parent directories)
</ParamField>

<ParamField path="url" type="Url" required>
  Directory URL
</ParamField>

<ResponseField name="return" type="bool, Error|nil">
  Success boolean, or (false, error)
</ResponseField>

```lua theme={null}
-- Create single directory
local ok, err = fs.create("dir", url)

-- Create with parents
local ok, err = fs.create("dir_all", url)
```

### `fs.remove(type, url)`

Remove a file or directory.

<ParamField path="type" type="string" required>
  One of: `"file"`, `"dir"`, `"dir_all"` (recursive), `"dir_clean"` (only if empty)
</ParamField>

<ParamField path="url" type="Url" required>
  File/directory URL
</ParamField>

<ResponseField name="return" type="bool, Error|nil">
  Success boolean, or (false, error)
</ResponseField>

```lua theme={null}
-- Remove file
fs.remove("file", file_url)

-- Remove directory recursively
fs.remove("dir_all", dir_url)

-- Remove only if empty
fs.remove("dir_clean", dir_url)
```

### `fs.read_dir(dir, options)`

Read directory contents.

<ParamField path="dir" type="Url" required>
  Directory URL
</ParamField>

<ParamField path="options" type="table">
  Read options
</ParamField>

<ParamField path="options.glob" type="string">
  Glob pattern to filter files
</ParamField>

<ParamField path="options.limit" type="number">
  Maximum number of files to read (default: unlimited)
</ParamField>

<ParamField path="options.resolve" type="bool">
  Resolve symlinks and get full metadata (default: false)
</ParamField>

<ResponseField name="return" type="File[]|nil, Error">
  List of files, or (nil, error)
</ResponseField>

```lua theme={null}
local files, err = fs.read_dir(url, {
  glob = "*.lua",
  limit = 100,
  resolve = true
})

if files then
  for _, file in ipairs(files) do
    ya.dbg(file.url)
  end
end
```

## File Metadata

### `fs.cha(url, follow?)`

Get file characteristics (metadata).

<ParamField path="url" type="Url" required>
  File URL
</ParamField>

<ParamField path="follow" type="bool">
  Follow symlinks (default: false)
</ParamField>

<ResponseField name="return" type="Cha|nil, Error">
  File characteristics, or (nil, error)
</ResponseField>

```lua theme={null}
local cha, err = fs.cha(url, true)
if cha then
  ya.dbg("Size: " .. cha.len)
  ya.dbg("Is dir: " .. tostring(cha.is_dir))
end
```

#### Cha Fields

* `len` (number) - File size in bytes
* `is_dir` (bool) - Is directory
* `is_hidden` (bool) - Is hidden file
* `is_link` (bool) - Is symbolic link
* `is_orphan` (bool) - Is orphan symlink
* `is_block` (bool) - Is block device
* `is_char` (bool) - Is character device
* `is_fifo` (bool) - Is FIFO
* `is_sock` (bool) - Is socket
* `is_exec` (bool) - Is executable
* `is_sticky` (bool) - Has sticky bit
* `modified` (number) - Last modified time (timestamp)
* `accessed` (number) - Last accessed time (timestamp)
* `created` (number) - Created time (timestamp)
* `permissions` (string) - Unix permissions string (e.g., "rwxr-xr-x")

### `fs.calc_size(url)`

Calculate total size of a directory (async iterator).

<ParamField path="url" type="Url" required>
  Directory URL
</ParamField>

<ResponseField name="return" type="SizeCalculator|nil, Error">
  Size calculator iterator, or (nil, error)
</ResponseField>

```lua theme={null}
local calc, err = fs.calc_size(url)
if calc then
  repeat
    local progress = calc:next()
    if progress then
      ya.dbg("Size: " .. progress.size)
    end
  until not progress
end
```

## Utilities

### `fs.unique(type, url)`

Create a unique file or directory name (handles naming conflicts).

<ParamField path="type" type="string" required>
  Either `"file"` or `"dir"`
</ParamField>

<ParamField path="url" type="Url" required>
  Desired URL (may be modified to be unique)
</ParamField>

<ResponseField name="return" type="Url|nil, Error">
  Unique URL, or (nil, error)
</ResponseField>

```lua theme={null}
local unique_url, err = fs.unique("file", url)
-- If /path/file.txt exists, may return /path/file (1).txt
```

<Note>
  This replaces the deprecated `fs.unique_name()` to fix TOCTOU race conditions. See [#3677](https://github.com/sxyazi/yazi/pull/3677).
</Note>

### `fs.cwd()`

Get the current working directory.

<ResponseField name="return" type="Url|nil, Error">
  Current directory URL, or (nil, error)
</ResponseField>

```lua theme={null}
local cwd, err = fs.cwd()
```

### `fs.expand_url(value)`

Expand `~` and environment variables in a URL/path string.

<ParamField path="value" type="string|Url" required>
  URL string or Url object
</ParamField>

<ResponseField name="return" type="Url">
  Expanded URL
</ResponseField>

```lua theme={null}
local url = fs.expand_url("~/documents")
-- Url("/home/user/documents")
```

### `fs.partitions()`

Get list of mounted partitions.

<ResponseField name="return" type="table[]">
  List of partition info tables
</ResponseField>

```lua theme={null}
local parts = fs.partitions()
for _, p in ipairs(parts) do
  ya.dbg(string.format("%s -> %s (%s)", p.src, p.dist, p.fstype))
end
```

Each partition table contains:

* `src` (string) - Device path
* `dist` (string) - Mount point
* `label` (string) - Volume label
* `fstype` (string) - Filesystem type
* `external` (bool) - Is external drive
* `removable` (bool) - Is removable media

## File Operations Helper

### `fs.op(name, options)`

Low-level file operation helper (internal use).

<ParamField path="name" type="string" required>
  Operation name: `"part"`, `"done"`, `"size"`
</ParamField>

<ParamField path="options" type="table" required>
  Operation-specific options
</ParamField>

This is used internally by Yazi for progress tracking of file operations.
