API Docs

Module for filesystem operations.

hs.fs provides a comprehensive set of filesystem operations covering file I/O, directory management, path manipulation, metadata access, symbolic links, Finder tags, and macOS-specific features like file bookmarks and Uniform Type Identifiers.

It replaces both Hammerspoon v1's hs.fs module and the functionality that was previously available through Lua's built-in io and file modules.

Reading and writing files

const contents = hs.fs.read("/etc/hosts");           // entire file
const chunk    = hs.fs.read("/etc/hosts", 100, 50);  // 50 bytes from offset 100

hs.fs.readLines("/etc/hosts", function(line) {
    console.log(line);
    return true; // return false to stop early
});

hs.fs.write("/tmp/hello.txt", "Hello, world!\n");
hs.fs.append("/tmp/hello.txt", "More content\n");

Directory operations

hs.fs.mkdir("~/Projects/new-thing");

const files = hs.fs.list("~/Documents");
const all   = hs.fs.listRecursive("~/Documents");

Path utilities

const abs  = hs.fs.pathToAbsolute("~/Library");
const tmp  = hs.fs.temporaryDirectory();
const home = hs.fs.homeDirectory();

Metadata

const info = hs.fs.attributes("/etc/hosts");
// { size: 1234, type: "file", permissions: 420,
//   ownerID: 0, groupID: 0,
//   creationDate: 1700000000.0, modificationDate: 1700001000.0 }

Properties

This module has no properties.

Methods

hs.fs.read(path, offset, length) -> string

Read part or all of a file as a UTF-8 string.
hs.fs.read(path, offset, length) -> string
Name Type Description
path string Path to the file. `~` is expanded.
offset number Byte offset to start reading from. Pass `0` (or omit) to read from the beginning.
length number Maximum number of bytes to read. Pass `0` (or omit) to read to the end of the file.
string
The file contents as a UTF-8 string, or `null` if the file cannot be read.
const all   = hs.fs.read("/etc/hosts")            // entire file
const chunk = hs.fs.read("/etc/hosts", 100, 50)   // 50 bytes starting at byte 100

hs.fs.readLines(path, callback) -> boolean

Read a file line-by-line, invoking a callback for each line. Lines are delivered with newline characters stripped. Both `\n` and `\r\n` line endings are handled.
hs.fs.readLines(path, callback) -> boolean
Name Type Description
path string Path to the file. `~` is expanded.
callback JSValue Called once per line with the line text. Return `true` to continue reading, or `false` to stop early.
boolean
`true` if the file was read successfully (including early stops requested by the callback), or `false` if the file could not be opened.
hs.fs.readLines("/etc/hosts", (line) => {
    if (line.startsWith("#")) return true
    console.log(line)
    return true
})

hs.fs.write(path, content, inPlace) -> boolean

Write a UTF-8 string to a file, creating it or overwriting any existing content. Intermediate directories are not created automatically; use `mkdir` first if needed.
hs.fs.write(path, content, inPlace) -> boolean
Name Type Description
path string Path to the file. `~` is expanded.
content string String to write.
inPlace boolean Whether to write the file in-place or atomically. Defaults to atomically
boolean
`true` on success, `false` on failure.
hs.fs.write("/tmp/hello.txt", "Hello, world!\n")

hs.fs.append(path, content) -> boolean

Append a UTF-8 string to a file, creating it if it does not exist.
hs.fs.append(path, content) -> boolean
Name Type Description
path string Path to the file. `~` is expanded.
content string String to append.
boolean
`true` on success, `false` on failure.
hs.fs.append("/tmp/log.txt", "another line\n")

hs.fs.exists(path) -> boolean

Determine if a filesystem object exists at the given path Unlike `isFile` and `isDirectory`, this follows symlinks.
hs.fs.exists(path) -> boolean
Name Type Description
path string Path to check. `~` is expanded.
boolean
`true` if any filesystem entry (file, directory, symlink, etc.) exists at the path.
if (hs.fs.exists("/tmp/file.txt")) console.log("exists")

hs.fs.isFile(path) -> boolean

Determine if a file exists at the given path This does **not** follow symlinks; a symlink pointing at a file returns `false`.
hs.fs.isFile(path) -> boolean
Name Type Description
path string Path to check. `~` is expanded.
boolean
`true` if a regular file (not a directory or symlink) exists at the path.
console.log(hs.fs.isFile("/etc/hosts"))

hs.fs.isDirectory(path) -> boolean

Determine if a directory exists at the given path This does **not** follow symlinks; a symlink pointing at a directory returns `false`.
hs.fs.isDirectory(path) -> boolean
Name Type Description
path string Path to check. `~` is expanded.
boolean
`true` if a directory exists at the path.
console.log(hs.fs.isDirectory("/tmp"))

hs.fs.isReadable(path) -> boolean

Determine if a given filesystem path is readable
hs.fs.isReadable(path) -> boolean
Name Type Description
path string Path to check. `~` is expanded.
boolean
`true` if the current process can read the file or directory at the path.
console.log(hs.fs.isReadable("/etc/hosts"))

hs.fs.isWritable(path) -> boolean

Determine if a given filesystem path is writable
hs.fs.isWritable(path) -> boolean
Name Type Description
path string Path to check. `~` is expanded.
boolean
`true` if the current process can write to the file or directory at the path.
console.log(hs.fs.isWritable("/tmp"))

hs.fs.copy(source, destination) -> boolean

Copy a file or directory to a new location. The destination must not already exist. If `source` is a directory, its entire contents are copied recursively.
hs.fs.copy(source, destination) -> boolean
Name Type Description
source string Path to the existing file or directory. `~` is expanded.
destination string Path for the copy. `~` is expanded.
boolean
`true` on success, `false` on failure.
hs.fs.copy("/tmp/a.txt", "/tmp/b.txt")

hs.fs.move(source, destination) -> boolean

Move (rename) a file or directory. The destination must not already exist.
hs.fs.move(source, destination) -> boolean
Name Type Description
source string Path to the existing file or directory. `~` is expanded.
destination string New path. `~` is expanded.
boolean
`true` on success, `false` on failure.
hs.fs.move("/tmp/old.txt", "/tmp/new.txt")

hs.fs.delete(path) -> boolean

Delete a file or directory. Directories are removed recursively. To remove only an empty directory, use `rmdir` instead.
hs.fs.delete(path) -> boolean
Name Type Description
path string Path to delete. `~` is expanded.
boolean
`true` on success, `false` on failure.
hs.fs.delete("/tmp/old.txt")

hs.fs.list(path) -> [String]

List the immediate contents of a directory. Returns bare filenames (not full paths), sorted alphabetically. The `.` and `..` entries are never included.
hs.fs.list(path) -> [String]
Name Type Description
path string Path to the directory. `~` is expanded.
[String]
Sorted array of filenames, or `null` if the path cannot be read.
const files = hs.fs.list("~/Documents")

hs.fs.listRecursive(path) -> [String]

Recursively list all entries under a directory. Returns paths relative to `path`, sorted alphabetically.
hs.fs.listRecursive(path) -> [String]
Name Type Description
path string Path to the root directory. `~` is expanded.
[String]
Sorted array of relative paths, or `null` if the path cannot be read.
const all = hs.fs.listRecursive("~/Documents")

hs.fs.mkdir(path) -> boolean

Create a directory, including all necessary intermediate directories. Succeeds silently if the directory already exists.
hs.fs.mkdir(path) -> boolean
Name Type Description
path string Path of the directory to create. `~` is expanded.
boolean
`true` on success, `false` on failure.
hs.fs.mkdir("~/Projects/new-thing")

hs.fs.rmdir(path) -> boolean

Remove an empty directory. Fails if the directory is not empty. Use `delete` to remove a non-empty directory recursively.
hs.fs.rmdir(path) -> boolean
Name Type Description
path string Path of the directory to remove. `~` is expanded.
boolean
`true` on success, `false` on failure.
hs.fs.rmdir("/tmp/empty-dir")

hs.fs.currentDir() -> string

Returns the current working directory of the process.
hs.fs.currentDir() -> string
string
Current directory path, or `null` on error.
console.log(hs.fs.currentDir())

hs.fs.chdir(path) -> boolean

Change the current working directory of the process.
hs.fs.chdir(path) -> boolean
Name Type Description
path string New working directory path. `~` is expanded.
boolean
`true` on success, `false` on failure.
hs.fs.chdir("~/Projects")

hs.fs.pathToAbsolute(path) -> string

Resolve a path to its absolute, canonical form. Expands `~`, resolves `.` and `..`, and follows all symbolic links. Returns `null` if any component of the path does not exist.
hs.fs.pathToAbsolute(path) -> string
Name Type Description
path string Path to resolve.
string
Absolute canonical path, or `null` if it cannot be resolved.
console.log(hs.fs.pathToAbsolute("~/Library"))

hs.fs.displayName(path) -> string

Return the localised display name for a file or directory as shown by Finder. For example, `/Library` appears as `"Library"` in Finder even though its on-disk name is the same.
hs.fs.displayName(path) -> string
Name Type Description
path string Path to the file or directory. `~` is expanded.
string
Display name string, or `null` if the path does not exist.
console.log(hs.fs.displayName("/Library"))

hs.fs.temporaryDirectory() -> string

Returns the temporary directory for the current user.
hs.fs.temporaryDirectory() -> string
string
Temporary directory path (always ends with `/`).
console.log(hs.fs.temporaryDirectory())

hs.fs.homeDirectory() -> string

Returns the home directory for the current user.
hs.fs.homeDirectory() -> string
string
Home directory path string.
console.log(hs.fs.homeDirectory())

hs.fs.urlFromPath(path) -> string

Returns a `file://` URL string for the given path.
hs.fs.urlFromPath(path) -> string
Name Type Description
path string Filesystem path. `~` is expanded.
string
URL string
console.log(hs.fs.urlFromPath("/tmp/foo.txt"))
// → "file:///tmp/foo.txt"

hs.fs.attributes(path) -> NSDictionary

Get metadata attributes for a file or directory. Does not follow symbolic links. Use `isSymlink` to detect links before calling this if needed.
hs.fs.attributes(path) -> NSDictionary
Name Type Description
path string Path to inspect. `~` is expanded.
NSDictionary
Attributes object, or `null` if the path cannot be accessed.
const info = hs.fs.attributes("/etc/hosts")
console.log(info.size, info.type)

hs.fs.touch(path) -> boolean

Update the modification timestamp of a file to the current time. Creates the file if it does not exist (equivalent to the POSIX `touch` command).
hs.fs.touch(path) -> boolean
Name Type Description
path string Path to the file. `~` is expanded.
boolean
`true` on success, `false` on failure.
hs.fs.touch("/tmp/marker.txt")

hs.fs.tags(path) -> [String]

Get the Finder tags assigned to a file or directory.
hs.fs.tags(path) -> [String]
Name Type Description
path string Path to the file or directory. `~` is expanded.
[String]
Array of tag name strings, or `null` if no tags are set.
console.log(hs.fs.tags("~/Documents/report.pdf"))

hs.fs.fileUTI(path) -> string

Replace all Finder tags on a file or directory. This function is only available on macOS Tahoe (26) or later.
hs.fs.fileUTI(path) -> string
Name Type Description
path string Path to the file.
string
`true` on success, `false` on failure.
hs.fs.setTags("~/Documents/report.pdf", ["Important", "Work"])
hs.fs.addTags("~/Documents/report.pdf", ["Reviewed"])
hs.fs.removeTags("~/Documents/report.pdf", ["Draft"])
console.log(hs.fs.fileUTI("/etc/hosts"))    // → "public.plain-text"
console.log(hs.fs.fileUTI("/tmp/foo.png"))  // → "public.png"

hs.fs.pathToBookmark(path) -> string

Encode a file path as a persistent bookmark that survives file moves and renames. The returned string is base64-encoded bookmark data that can be stored and later resolved with `pathFromBookmark`.
hs.fs.pathToBookmark(path) -> string
Name Type Description
path string Path to the file or directory. `~` is expanded.
string
Base64-encoded bookmark string, or `null` on failure.
const data = hs.fs.pathToBookmark("/tmp/foo.txt")

hs.fs.pathFromBookmark(data) -> string

Resolve a base64-encoded bookmark back to a file path.
hs.fs.pathFromBookmark(data) -> string
Name Type Description
data string Base64-encoded bookmark string produced by `pathToBookmark`.
string
The current file path, or `null` if the bookmark cannot be resolved.
const path = hs.fs.pathFromBookmark(savedData)