npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@babashka/fs

v0.5.34

Published

File system utilities for Clojure/ClojureScript.

Readme

babashka.fs

Clojars Project ci bb built-in

File system utilities. This library can be used from:

  • Clojure on the JVM - we support Clojure 1.10.3 and above on Java 11 and above.
  • babashka - it has been a built-in library since babashka v0.2.9.

Why

Babashka is a scripting utility. It's convenient to have cross platform file system utilities available for scripting. The namespace clojure.java.io already offers a bunch of useful features, but it predates java.nio. The nio package isn't that nice to use from Clojure and this library should help with that.

The main inspirations for this library are clojure.java.io, clj-commons/fs and corasaurus-hex/fs.

API docs

See API.md.

Usage

in JVM Clojure, add this library to your deps.edn file. This library is built-in in babashka, so it works out of the box there.

;; deps.edn
babashka/fs {:mvn/version "<version>"}
(require '[babashka.fs :as fs])
(fs/directory? ".") ;;=> true

Examples

The glob function takes a root path and a pattern. The pattern is interpreted as documented here.

(map str (fs/glob "." "**{.clj,cljc}"))

Output:

("project.clj" "test/babashka/fs_test.clj" "src/babashka/fs.cljc")

The function exec-paths returns all entries from PATH as Paths. To search all these directories for an executable, e.g. java, you can combine it with list-dirs which searches files directly in the directories using an (optional) glob pattern:

(str (first (filter fs/executable? (fs/list-dirs (filter fs/exists? (fs/exec-paths)) "java"))))
"/Users/borkdude/.jenv/versions/11.0/bin/java"

For convenience, the above use case is also supported using the which function:

(str (fs/which "java"))
"/Users/borkdude/.jenv/versions/11.0/bin/java"

Node.js

Babashka.fs is supported on Node.js via ClojureScript, squint and JS directly (via compiled squint). The JVM behavior is the leading reference implementation so all operations are synchronous. If you need async support then this port is not for you. The intended use case for babashka.fs on Node.js is mainly scripting, e.g. using nbb. From ClojureScript and nbb, depend on this library as a regular Clojure dependency and require babashka.fs as on the JVM. From squint, either require the npm package as a JS library ((:require ["@babashka/fs" :as fs])), or use a git dep for the source, which is needed for the with-temp-dir macro. From JavaScript, use the npm package. The JavaScript API accepts JS objects directly.

In JavaScript you can install this library with:

npm install @babashka/fs
import * as fs from '@babashka/fs';
fs.exists("README.md") //=> true

JS naming conventions

In JS, kebab-case functions are exported under their munged versions (kebab_case) as well as their JS-idiomatic camelCase counterparts. Predicates either drop the question mark or get an is prefix. Option maps accept both camelCase and dashed keys.

| Clojure | JavaScript | |---------|------------| | (fs/copy-tree src dst) | fs.copyTree(src, dst) | | (fs/directory? p) | fs.isDirectory(p) | | (fs/exists? p) | fs.exists(p) | | (fs/copy src dst {:replace-existing true}) | fs.copy(src, dst, {replaceExisting: true}) |

Differences from the JVM

The API usage on Node.js should not be much different from the JVM, except:

  • Paths are always strings
  • File times are BigInt nanoseconds
  • zip/unzip are not supported (due to Node.js not having support for it natively)
  • set-creation-time is not supported: Node.js has no API to set a file's creation (birth) time
  • owner returns a uid instead of a username
  • the atomic-move option is ignored

This library is tested via ClojureScript (shadow-cljs), squint and nbb on Node.js. The squint and shadow-cljs builds also run on deno and bun, and squint additionally on Windows.

Notes

Coercions and Returns

Babashka fs functions automatically coerce input path args from File, Path, and string.

For example, these are all supported and equivalent:

(fs/exists? "foo")
(fs/exists? (java.io.File. "foo"))
(fs/exists? (.toPath (java.io.File. "foo")))

If you need a specific concrete type for a returned path, you can coerce it like so:

(str (fs/cwd))
(fs/path (fs/cwd))
(fs/file (fs/cwd))

Argument Naming Conventions

API argument names describe the value's logical role. For example, if an argument name contains:

| Argument Name | Argument Expects | |---------------|-------------------| | path | directory or file | | file | file | | dir | directory |

The argument name conveys the logical role of the value you pass; it does not describe its type. See Coercions and Returns.

File Systems & OSes & JDK Bugs

Behaviour can vary on different file systems and OSes.

The JDK file APIs have historically had some obscure bugs; we've described known issues that affect babashka fs below. The JDK team has fixed most of these bugs, so we encourage you to use the latest stable JDK, if you can.

If you uncover some interesting new unexpected behaviour, please let us know.

Windows & Links

You may have to enable the ability to create soft & hard links on Windows.

Empty String Paths

The underlying JDK file APIs (and, by extension, babashka.fs) typically consider an empty-string path "" to be the current working directory. This means that (fs/list-dir "") is functionally equivalent to (fs/list-dir ".").

umask

On Linux and macOS you can often optionally specify :posix-file-permissions. For newly created files and directories, these permissions are affected by your configured umask.

For example, let's say your umask masks out the others-write permission:

$ umask -S
u=rwx,g=rwx,o=rx

Notice that others-write, even though specified on creation, is masked out by umask:

(fs/create-file "afile" {:posix-file-permissions "rwxrwxrwx"})

;; umask affected resulting permissions of new files
(-> (fs/posix-file-permissions "afile") (fs/posix->str))
;; => "rwxrwxr-x"

This applies only to newly created files and directories. You can explicitly set permissions on existing files and directories:

(fs/create-dir "adir" {:posix-file-permissions "rwxrwxrwx"})

;; umask affected resulting permissions of new dirs
(-> (fs/posix-file-permissions "adir") (fs/posix->str))
;; => "rwxrwxr-x"

;; but you can explicitly override permissions on existing file & dirs like so:
(fs/set-posix-file-permissions "adir" "rwxrwxrwx")
(-> (fs/posix-file-permissions "adir") (fs/posix->str))
;; => "rwxrwxrwx"

This is the underlying behaviour the JDK file APIs, see Setting Initial Permissions in JavaDocs. Babashka fs, as a light wrapper, reflects this behaviour.

creation-time

Depending on which OS and JDK version you are running, creation-time might return unexpected results. As of this writing, our testing has revealed:

  • Windows - returns creation time as expected
  • macOS - returns creation time as expected
  • Linux - returns modified time before JDK 17, otherwise returns creation time as expected

See JDK-8316304.

set-creation-time

Depending on which OS and JDK version you are running, set-creation-time might not do what you would expect. As of this writing, our testing has revealed:

  • Windows - sets creation time as expected
  • macOS
    • after Java 17 sets creation time as expected, otherwise seems to have no effect
    • otherwise has no effect
  • Linux - seems to have no effect

See JDK-8151430

:nofollow-links

Many babashka.fs functions accept the :nofollow-links option. These functions will follow symbolic links unless you pass in {:nofollow-links true}.

On some JDK/OS combinations, set-attribute, set-last-modified-time, and touch may throw when attempting to set on the link itself. Considering latest JDK 11+ LTS releases only, at the time of this writing, we have found this bug on JDK 11 for both macOS and Linux and JDK 21 for Linux. For example, on JDK11 on Linux and macOS:

(spit "foo" "foo.txt")
(fs/create-sym-link "foo-link" "foo")
;; this works fine and sets last modified time on "foo":
(fs/set-last-modified-time "foo-link" (java.time.Instant/now))
;; when attempting to set time on link itself, throws on some JDK/OS combinations:
(fs/set-last-modified-time "foo-link" (java.time.Instant/now) {:nofollow-links true})
;; => Execution error (FileSystemException) 
;;    foo-link: Too many levels of symbolic links or unable to access attributes of symbolic link

On Windows, for JDK < 24, we have found that canonicalize will never follow symbolic links due to this JDK bug JDK-8003887.

:follow-links

Some babashka.fs functions accept the :follow-links option. These functions will not follow symbolic links unless you pass in {:follow-links true}.

glob

On macOS, for JDK < 26, functions that match on a glob pattern will omit filenames with Unicode characters that include a variant-selector due to this JDK bug JDK-8354490.

Test & Dev

To run all tests

$ bb test

You can also use cognitect test-runner options, for example, to run a single test:

bb test --var babashka.fs-test/walk-test

[!NOTE] To allow us to contrive isolated file system scenarios, tests are always run from the scratch current working directory ./target/test-cwd.

To fire up a REPL when working on babashka fs tests, you must run:

bb dev

API Docs

This project generates API docs with quickdoc, to regenerate API.md:

shell quickdoc

License

Copyright © 2020-2026 Michiel Borkent

Distributed under the EPL License, same as Clojure. See LICENSE.