ZFS Explorer is a web-based, read-only explorer for ZFS on-disk structures —
a visual frontend for zdb.
It allows interactive inspection of ZFS internals while preserving full object-level accuracy. The goal is not to abstract ZFS, but to make its on-disk format explorable, navigable, and debuggable.
ZFS Explorer currently supports:
- Pool configuration summary (zdb-style fields + vdev tree)
- Persistent pool error-log browsing (paged, with optional path resolution)
- MOS object browsing and inspection
- Dnode and blkptr decoding
- ZAP visualization
- Dataset and DSL graph traversal
- ZPL filesystem walking (directories and files)
- Raw block hex inspection via DVAs
The design is intentionally read-only. Long-term goals include supporting analysis of unimported or damaged pools, enabling forensic inspection and file recovery without ever importing the pool.
Current mode disclaimer: default operation is live imported pools.
Offline/exported pool analysis is supported and can be enabled explicitly via
env configuration or GET/PUT /api/mode (see Offline Mode below).
You can think of this project as:
zdb, visualized- A filesystem browser that never lies
- A teaching and debugging tool for ZFS internals
- A foundation for ZFS recovery and forensic workflows
Current Status: Active development (Milestones 0-6 complete; Release Readiness + Offline Mode work in progress)
For most users, the recommended path is:
- Download release artifacts from GitHub Releases:
zfs-explorer-<version-label>-<profile>-<os>-<arch>.tar.gz(backend)zfs-explorer-webui-<version-label>.tar.gz(optional static UI bundle)
- Run the backend on a host with ZFS access.
- Use either:
- the packaged UI bundle (
run-webui.sh), or - your own locally hosted UI that points to tunneled backend port
9000.
- the packaged UI bundle (
Latest releases:
Example backend startup from a release tarball:
tar -xzf zfs-explorer-<version-label>-release-<os>-<arch>.tar.gz
cd zfs-explorer-<version-label>-release-<os>-<arch>
sudo ./run-backend.shIf you want to build from source or generate custom packages, see Developer Guide below.
- Start backend on the ZFS host (
sudo ./run-backend.shorsudo ./target/debug/zfs-explorer). - Open the UI and pick a pool from the left pane.
- Use
Datasetsto choose a dataset, then browse its filesystem view. - Click
Open as object(or object links in Inspector) to jump into MOS/object inspection. - Use
Explore,Graph, andPhysicalcenter views to inspect semantic and blkptr relationships. - Use Inspector tabs (
Summary,ZAP,Blkptr,Raw) for detailed decoding and hex reads. - Use
Copy debugin Inspector when reporting bugs.
- Select dataset in
Datasetstree. - Browse paths in FS view (
ListorGraph). - Select an entry and click
Open as object. - Inspect bonus fields, ZAP links, blkptrs, and raw block hex.
- In MOS mode, open object
1(object directory) and inspect ZAP entries. - Follow
root_datasetto DSL dir objects. - Traverse
child_dir_zapobj/head_dataset_objedges. - Handoff into FS view from dataset-linked inspector actions.
Screenshots were captured on a high-DPI display. The README shows scaled previews for readability; click any image to open the full-resolution PNG.
ZFS Explorer is a monorepo with layered deliverables:
zfs-explorer-ui: the React web application (typically port8080)zdx-api(internal backend layer): Rust HTTP API service (typically port9000)libzdbdecode.so: native read-only decode layer over vendored OpenZFS userland
Data flow:
zfs-explorer-ui -> zdx-api -> libzdbdecode.so -> OpenZFS userland
API stability note:
- The API is currently internal-but-documented (
docs/API_REFERENCE.md). - Endpoint and payload churn is still expected before a formal stability contract (targeting post-v1.0 hardening).
- ✅ Pool discovery/open for imported pools with read-only safety model
- ✅ MOS browser with pagination, filtering, semantic + physical graph views
- ✅ Rich inspector for dnode fields, ZAP, blkptrs, and raw hex block reads
- ✅ Pool summary view with feature list, collapsible vdev tree, and copyable zdb-like output
- ✅ DSL-aware traversal and dataset tree navigation
- ✅ Filesystem navigation (list + graph modes) with dataset/mount handoff
- ✅ SPA history-friendly UI navigation, breadcrumbs, and object pinning
- ✅ Packaging/build scripts and offline fixture + parity validation tooling
This section is for contributors and operators building custom artifacts. End users should prefer release tarballs from GitHub Releases.
Use the platform bootstrap script first, then run the normal build.
Debian:
build/bootstrap-debian.sh
build/build.sh --bootstrap-openzfsUbuntu:
build/bootstrap-ubuntu.sh
build/build.sh --bootstrap-openzfsFreeBSD:
build/bootstrap-freebsd.sh
build/build.sh --bootstrap-openzfsNotes:
build/build.shusesgmakeautomatically on FreeBSD (orMAKEif set).- On Ubuntu,
zfsutils-linuxis required for corpus fixture create/test scripts. - If UI build warns about Node version, upgrade to Node
>= 20.19for Vite 7.
If your UI runs in a container/VM without ZFS access, run the backend on a host
that can see /dev/zfs, then tunnel the ports.
If you are an end user, use release tarballs from GitHub Releases instead of
building with build/package.sh.
Recommended workflow: package both deliverables once, copy only the backend tarball to the ZFS host, and run only the backend there. The UI can stay on your local machine (or another box).
# Produces:
# - dist/zfs-explorer-<version-label>-release-<os>-<arch>.tar.gz
# - dist/zfs-explorer-webui-<version-label>.tar.gz
./build/package.sh --profile release
# Optional: pin an explicit label instead of auto git describe/sha.
# ./build/package.sh --profile release --version-label v1.0.0-rc1# Adjust OS/arch/USER/HOST to your environment.
OS_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')"
ARCH_NAME="$(uname -m)"
TARBALL="$(ls -1 dist/zfs-explorer-*-release-${OS_NAME}-${ARCH_NAME}.tar.gz | sort | tail -n1)"
scp "$TARBALL" USER@HOST:/tmp/ssh USER@HOST
mkdir -p ~/zfs-explorer
OS_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')"
BACKEND_TAR="$(ls -1 /tmp/zfs-explorer-*-release-${OS_NAME}-$(uname -m).tar.gz | sort | tail -n1)"
tar -xzf "$BACKEND_TAR" -C ~/zfs-explorer --strip-components=1
cd ~/zfs-explorer
sudo ./run-backend.shExpected output:
INFO zfs_explorer: Initializing ZFS library...
INFO zfs_explorer: ZFS Explorer (...)
INFO zfs_explorer: API server listening on 127.0.0.1:9000
# Terminal 1: local -> ZFS host backend
ssh -L 9000:127.0.0.1:9000 USER_ZFS@ZFS_HOST
# Terminal 2: run UI locally
cd ui
npm run dev
# Open http://127.0.0.1:8080# Terminal 1: local -> build box UI
ssh -L 8080:127.0.0.1:8080 USER_BUILD@BUILD_HOST
# Terminal 2: local -> ZFS host backend
ssh -L 9000:127.0.0.1:9000 USER_ZFS@ZFS_HOST
# Open http://127.0.0.1:8080 on your local machineThis works because the UI currently targets http://localhost:9000, so your
browser reaches the backend through your local 9000 tunnel.
ssh -L 8080:127.0.0.1:8080 -L 9000:127.0.0.1:9000 USER@HOST
# UI on localhost:8080, backend on localhost:9000Tunnel reliability tip:
- Keep long-lived tunnel sessions in
tmuxorscreenso they survive local terminal disconnects/restarts.
Backend startup now supports an explicit offline pool-open mode for exported pools. This mode is opt-in and remains read-only.
Runtime switching is also available from the UI header (Mode: Live | Offline)
or directly via GET/PUT /api/mode.
export ZFS_EXPLORER_POOL_MODE=offline
export ZFS_EXPLORER_OFFLINE_POOLS="poolA,poolB"
export ZFS_EXPLORER_OFFLINE_PATHS="/dev/disk/by-id:/srv/offline-images"
sudo ./run-backend.shEnvironment variables:
ZFS_EXPLORER_POOL_MODE:live(default) orofflineZFS_EXPLORER_OFFLINE_POOLS: comma-separated pool names exposed by/api/poolsin offline modeZFS_EXPLORER_OFFLINE_PATHS: colon-separated search paths used by offline open logicZFS_EXPLORER_ZPOOL_CACHEFILE: optional override for pool cachefile path in live mode (useful on hosts that do not use/etc/zfs/zpool.cache, e.g./data/zfs/zpool.cache)
Offline troubleshooting:
- API errors now return a structured envelope:
code(for exampleEZFS_NOENT,ERRNO_13)message- optional
hint
- Typical fixes:
EZFS_NOENT: pool metadata was not found in the configured search pathsEZFS_PERM/ERRNO_13: backend needs root/raw-device read accessEZFS_ACTIVE_POOL: export pool before opening in offline mode
Direct file recovery download (live or offline):
# Download by dataset path (or absolute mounted path), with attachment headers
curl -fL -o recovered.bin \
"http://127.0.0.1:9000/api/pools/testpool/zpl/path/testpool/myds/path/file.bin"
# Resume a partial transfer via HTTP Range
curl -fL -C - -o recovered.bin \
"http://127.0.0.1:9000/api/pools/testpool/zpl/path/testpool/myds/path/file.bin"
# Explicit single-range request
curl -fL \
-H "Range: bytes=0-1048575" \
"http://127.0.0.1:9000/api/pools/testpool/zpl/path/testpool/myds/path/file.bin" \
-o chunk-0.bin
# Objset-scoped download (works for dataset heads and snapshots)
curl -fL -o recovered.bin \
"http://127.0.0.1:9000/api/pools/testpool/objset/72/zpl/path/data/docs/readme.txt"Recursive dataset/snapshot recovery (CLI-first):
# Recover an entire dataset subtree
python tools/recover-files.py \
--backend http://127.0.0.1:9000 \
--filesystem zpool/data \
--path /docs \
--destination /tmp/recovered-docs
# Recover from a snapshot
python tools/recover-files.py \
--backend http://127.0.0.1:9000 \
--filesystem zpool/data@snap-2026-02-20 \
--destination /tmp/recovered-snapshot
# Force streaming ZPL download for dataset heads
python tools/recover-files.py \
--backend http://127.0.0.1:9000 \
--filesystem zpool/data \
--destination /tmp/recovered \
--download-method zpl
# Auto-start backend if needed (operator-supplied command)
python tools/recover-files.py \
--backend http://127.0.0.1:9000 \
--filesystem zpool/data \
--destination /tmp/recovered \
--start-backend-if-needed \
--start-backend-cmd "sudo ./run-backend.sh"By default, the tool writes:
- per-file NDJSON manifest:
<destination>/recover-manifest.ndjson - run summary JSON:
<destination>/recover-summary.json <file>.FAILED.jsonsidecars for files that could not be recovered
Optional parity check workflow (live vs offline responses):
# live backend on :9000, offline backend on :9001
LIVE_BASE_URL=http://127.0.0.1:9000 \
OFFLINE_BASE_URL=http://127.0.0.1:9001 \
build/check-offline-parity.sh <pool> 1 32 34Create a local offline fixture pool and run offline smoke checks:
# create/export a small file-backed fixture pool
build/create-offline-fixture.sh --pool zdx_fixture --force
# run backend smoke checks against that fixture (root required)
sudo build/test-offline-fixture.sh \
--pool zdx_fixture \
--search-paths "$(pwd)/fixtures/offline/zdx_fixture"Create and validate corpus fixtures (layout/profile matrix):
# generate exported corpus fixture
build/create-corpus-fixture.sh \
--pool zdx_mirror_base \
--layout mirror \
--profile baseline \
--force
# generate encrypted dataset fixture (no key material available offline)
build/create-corpus-fixture.sh \
--pool zdx_enc_nokey \
--layout single \
--profile encryption-no-key \
--force
# run smoke checks + file checksum validation from manifest
sudo build/test-corpus-fixture.sh \
--manifest fixtures/corpus/vdevtype=mirror/features=baseline/zdx_mirror_base/manifest.json
# run the default minimal corpus subset (mirror + raidz1 + encryption-no-key)
sudo build/test-corpus-subset.sh --list
sudo build/test-corpus-subset.sh
# create the full layout/profile matrix (54 combinations by default)
build/create-corpus-matrix.sh --list
build/create-corpus-matrix.sh --force
# validate every discovered manifest in the selected matrix
sudo build/test-corpus-matrix.sh --list
sudo build/test-corpus-matrix.sh --keep-goingQuick API sanity checks (backend runs on 127.0.0.1:9000):
curl -s http://127.0.0.1:9000/api/pools | jq
curl -s http://127.0.0.1:9000/api/pools/<pool>/summary | jqRun a focused OpenZFS ZTS smoke set (non-root user with passwordless sudo):
# list default "corpus" smoke tests
build/run-zts-smoke.sh --list
# run corpus profile smoke checks using sparse file-vdevs
build/run-zts-smoke.sh --profile corpus
# continue after failures and include extra zfs-tests.sh args
build/run-zts-smoke.sh --profile extended --keep-going -- -vzfs-explorer/
├── zfs/ # OpenZFS submodule (commit 21bbe7cb6)
├── _deps/openzfs/ # Built OpenZFS userland
├── native/ # C wrapper (libzdbdecode)
│ ├── include/
│ │ └── zdbdecode.h # Public API
│ ├── src/
│ │ ├── zdbdecode_internal.h
│ │ ├── zdx_core.c
│ │ ├── zdx_pool.c
│ │ ├── zdx_mos.c
│ │ ├── zdx_dsl.c
│ │ ├── zdx_objset.c
│ │ ├── zdx_catalog.c
│ │ ├── zdx_zap.c
│ │ ├── zdx_block.c
│ │ ├── json.c # JSON helpers
│ │ └── json.h
│ ├── libzdbdecode.so # Built library
│ └── Makefile
├── backend/ # Rust server
│ ├── Cargo.toml
│ ├── build.rs # FFI bindings
│ └── src/
│ ├── main.rs # Entry point
│ ├── ffi/ # Safe FFI wrappers
│ └── api/ # API handlers
└── ui/ # React frontend
├── package.json
└── src/
├── App.tsx # Main component
└── App.css
Full endpoint reference (all registered routes, params, and notes):
docs/API_REFERENCE.md
Commonly used endpoints:
GET /api/version- Build/runtime/debug metadata (includes active pool-open mode)GET /api/pools- List pools visible in current modeGET /api/pools/{pool}/summary- Structured pool config summaryGET /api/pools/{pool}/datasets/tree- Dataset hierarchy for a poolGET /api/pools/{pool}/objset/{objset_id}/walk?path=/a/b- Path walk within objsetGET /api/pools/{pool}/zpl/path/{*zpl_path}- File download by ZPL path (singleRangesupported)
zfs/ is an OpenZFS git submodule and is required for native/backend builds.
For the current 1.0 RC line, the repo pins an OpenZFS compatibility commit used
to tolerate older distro kernel modules, including older Ubuntu ZFS module
packages. That commit currently lives in the mminkus/zfs fork, so the
submodule URL points there to keep fresh clones reproducible.
# fresh clone
git clone --recurse-submodules https://github.com/mminkus/zfs-explorer.git
cd zfs-explorer
# if you already cloned without submodules
git submodule update --init --recursiveIf you switch OpenZFS branches/tags in zfs/ (for example zfs-2.4.0 vs
master), do a clean re-sync before rebuilding to avoid mixed generated files.
git submodule update --init --recursive --force
git -C zfs reset --hard
git -C zfs clean -fdx
git -C zfs sparse-checkout disable || trueLocal build/build.sh runs this check in warning mode by default so maintainers
can experiment with OpenZFS rebases. Packaging/release scripts still fail fast
unless --allow-openzfs-drift is passed explicitly. If you want to restore the
pinned compat baseline, run:
git submodule update --init --recursiveQuick bootstrap (recommended on fresh Debian VMs):
./build/bootstrap-debian.shThis installs apt dependencies, host OpenZFS runtime packages, and initializes
submodules. Then continue with ./build/build.sh --bootstrap-openzfs.
Manual install:
sudo apt-get update
sudo apt-get install -y \
git build-essential autoconf automake libtool pkg-config m4 gawk \
libssl-dev libelf-dev libudev-dev libblkid-dev uuid-dev zlib1g-dev \
libzstd-dev libtirpc-dev clang libclang-dev \
python3 python3-pip python3-setuptools python3-cffi libffi-dev \
nodejs npm curl jqInstall Rust (if cargo is missing):
curl https://sh.rustup.rs -sSf | sh
source "$HOME/.cargo/env"Node 20+ is recommended for current Vite/TypeScript tooling.
Backend note: Rust bindgen requires libclang at build time. If you see
Unable to find libclang, ensure clang and libclang-dev are installed.
For live pool access (/dev/zfs) and CLI-backed telemetry (zpool, zfs),
install Debian OpenZFS packages from backports.
# enable backports (adjust if your host manages apt sources differently)
echo "deb http://deb.debian.org/debian $(. /etc/os-release; echo $VERSION_CODENAME)-backports main contrib" \
| sudo tee /etc/apt/sources.list.d/backports.list
sudo apt-get update
sudo apt-get install -y -t "$( . /etc/os-release; echo $VERSION_CODENAME)-backports" \
zfsutils-linux zfs-dkms zfs-zed
# optional test tooling
sudo apt-get install -y -t "$( . /etc/os-release; echo $VERSION_CODENAME)-backports" zfs-test
# optional: required for build/run-zts-smoke.sh (ZTS uses ksh tests)
sudo apt-get install -y kshNotes:
- This project builds against the vendored
zfs/submodule, not distro OpenZFS headers/libs. - The currently pinned
zfs/commit carries the compatibility baseline we use for older distro kernel modules. Release builds should use the pinned submodule state, not an arbitrary localzfs/branch. Local builds warn on drift by default; package/release scripts stay strict unless explicitly run with--allow-openzfs-drift. - The submodule points at
mminkus/zfsbecause the pinned compatibility commit is not part of upstreamopenzfs/zfs. Maintainers working on rebases can add anupstreamremote insidezfs/as needed. - Host OpenZFS packages are still needed to access imported pools in live mode.
- After
zfs-dkmsinstall/upgrade, a reboot ormodprobe zfsmay be required. - Debian backports currently tracks OpenZFS 2.4.0. If you want strict
parity testing against those host packages, you can temporarily check out
zfs-2.4.0in thezfs/submodule for local builds:git -C zfs checkout zfs-2.4.0and switch back to the repo-pinned baseline with:git submodule update --init --recursive.
Canonical build entrypoint:
# Full build (native + backend + UI build)
./build/build.shFast local rebuild loop:
# Equivalent to: native clean+make, backend build+unit tests,
# native unit tests, UI build
./build/build.sh --quickQuick local unit-test loop:
# backend unit tests + native unit tests + optional UI build
./build/test-quick.sh
# skip UI build when iterating backend/native only
./build/test-quick.sh --skip-ui-buildTesting policy and scope split (unit vs fixture) are documented in
docs/TESTING_STRATEGY.md.
If you need to bootstrap vendored OpenZFS userland as well:
./build/build.sh --bootstrap-openzfsManual equivalent (reference):
# 1. Build OpenZFS userland (one time)
cd zfs
./autogen.sh
./configure --prefix=$PWD/../_deps/openzfs --with-config=user --enable-debug
make -j$(nproc)
make install
cd ..
# 2. Build native library
cd native
make clean && make
cd ..
# 3. Build Rust backend (with baked-in rpath)
cd backend
source ~/.cargo/env
cargo build
cd ..
# The binary will have rpath set via .cargo/config.toml
# This means it can find its libraries without LD_LIBRARY_PATH
# 4. Install UI dependencies
cd ui
npm installIf OpenZFS fails with errors like:
No rule to make target 'libuutil.h', needed by 'all-am'- missing header mismatches after switching
zfs/commits
the issue is usually a stale/mixed OpenZFS source tree state, not a missing
system package. Reset and rebuild from a clean zfs/ tree:
git submodule update --init --recursive --force
git -C zfs reset --hard
git -C zfs clean -fdx
git -C zfs sparse-checkout disable || true
# Optional: choose a specific OpenZFS ref for parity testing
# git -C zfs checkout zfs-2.4.0
cd zfs
./autogen.sh
./configure --prefix="$PWD/../_deps/openzfs" --with-config=user --enable-debug
make -j"$(nproc)"
make installBuild two bundles:
- zdx-api backend bundle (binary + required shared libraries)
- web UI static bundle
# debug bundle
./build/package.sh
# release bundle
./build/package.sh --profile release
# package existing artifacts without rebuilding
./build/package.sh --skip-buildOutput:
- Backend directory:
dist/zfs-explorer-<version-label>-<profile>-<os>-<arch>/ - Backend tarball:
dist/zfs-explorer-<version-label>-<profile>-<os>-<arch>.tar.gz - Web UI directory:
dist/zfs-explorer-webui-<version-label>/ - Web UI tarball:
dist/zfs-explorer-webui-<version-label>.tar.gz
Run the packaged web UI bundle with:
WEBUI_TAR="$(ls -1 dist/zfs-explorer-webui-*.tar.gz | sort | tail -n1)"
tar -xzf "$WEBUI_TAR" -C /tmp
cd /tmp/"$(basename "$WEBUI_TAR" .tar.gz)"
./run-webui.sh 8080Run backend from the bundle with:
./run-backend.shIf your host requires elevated privileges to access pools, run:
sudo ./run-backend.shTypical remote-host flow:
# on build machine
./build/package.sh --profile release
OS_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')"
BACKEND_TAR="$(ls -1 dist/zfs-explorer-*-release-${OS_NAME}-$(uname -m).tar.gz | sort | tail -n1)"
rsync -av "$BACKEND_TAR" USER@HOST:/tmp/
# on target host
cd /opt
OS_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')"
BACKEND_TAR="$(ls -1 /tmp/zfs-explorer-*-release-${OS_NAME}-$(uname -m).tar.gz | sort | tail -n1)"
sudo tar -xzf "$BACKEND_TAR"
cd "$(basename "$BACKEND_TAR" .tar.gz)"
sudo ./run-backend.shUse build/package-matrix.sh to produce release artifacts for multiple
platforms in one run:
- Linux targets built in Docker:
debian12,debian13,ubuntu2204,ubuntu2404,ubuntu2504,rocky9,alma10 - FreeBSD target built via SSH on a remote host
# Default matrix:
# - Linux: debian12, debian13, ubuntu2204, ubuntu2404, ubuntu2504, rocky9, alma10
# - FreeBSD: skipped by default
./build/package-matrix.sh
# Linux + FreeBSD
./build/package-matrix.sh --freebsd-host freebsd.example.net
# FreeBSD only (explicit host required)
./build/package-matrix.sh --skip-linux --freebsd-host freebsd.example.netOutputs are written under dist/releases/<utc-timestamp>/ and include:
- distro-labeled backend tarballs under
linux/andfreebsd/ - shared
zfs-explorer-webui-<version-label>.tar.gz SHA256SUMS.txtfor generated tarballsMATRIX_SUMMARY.txt(run metadata + pass/fail summary)matrix-logs-<utc-timestamp>.tar.gz(archived logs for support triage)
Notes:
- Linux matrix requires Docker on the host.
- FreeBSD matrix is opt-in and requires
--freebsd-host, passwordless SSH/scp access, and the repo checked out at the same path (or pass--freebsd-repo). - Linux matrix builds the UI once locally unless
--skip-ui-buildis used. - Default version label is derived from git (
describe --tags --dirty --always); override with--version-label <label>for release candidates.
For the 1.0 announcement, we publish and smoke-test release tarballs for:
- Debian 13
- Ubuntu 24.04
- FreeBSD 15
- AlmaLinux 10 (EL10 family)
Additional matrix targets (Debian 12, Ubuntu 22.04/25.04, EL9) are validated regularly but are considered compatibility coverage, not primary release gates.
Maintainer release steps (build, verify, publish, and log archival) are documented in:
docs/RELEASE_PLAYBOOK.md
Note: full static backend linking is not the primary target right now.
See docs/PACKAGING_STATIC_FEASIBILITY.md for the current packaging decision.
- Backend binds to 127.0.0.1:9000 only (localhost)
- Access via SSH tunnel for remote use
- Requires root privileges (or ZFS capabilities) to access pools
- Native initialization uses
kernel_init(SPA_MODE_READ). - Live mode opens already-imported pools and does not issue write paths.
- Offline mode is explicit and uses read-only import plumbing for analysis.
- Native runtime guardrails reject pool access if read-only mode is not active.
- API bind address is localhost-only by default (
127.0.0.1:9000). - Offline/exported mode is supported and can be selected via env vars or
GET/PUT /api/mode.
This project is intended for inspection and debugging, not mutation.
For demos/recordings, a UI screenshot mode can anonymize selected sensitive JSON fields (hostname, GUIDs, hostid, and device path identifiers) while preserving object relationships.
See:
docs/SCREENSHOT_MODE.md
Known caveats and expected failure modes are tracked in:
docs/KNOWN_LIMITATIONS.md
FreeBSD development and validation notes:
docs/PORTABILITY_FREEBSD.md
Backend logging uses tracing with INFO as default if RUST_LOG is unset.
Common RUST_LOG presets:
# Default behavior (same as unset)
RUST_LOG=info sudo ./target/debug/zfs-explorer
# Quieter operation
RUST_LOG=warn sudo ./target/debug/zfs-explorer
# Debug ZFS Explorer backend routes and FFI flow
RUST_LOG=zfs_explorer=debug,axum=info,tower_http=info sudo ./target/debug/zfs-explorerDebug metadata endpoint:
curl http://127.0.0.1:9000/api/versionThe Inspector also provides a Copy debug action that copies backend version/runtime info plus current UI navigation context as JSON.
For repeatable milestone/release verification, use:
docs/VALIDATION_CHECKLIST.mddocs/TESTING_STRATEGY.mddocs/SCREENSHOTS.md
- Finish FS navigation + graph integration
- Add richer ZPL metadata decoding
- Expand graph tools and inspection workflows
| Component | Technology |
|---|---|
| Native | C + ZFS libraries |
| Backend | Rust + axum |
| Frontend | React 19 + TypeScript + Vite |
- OpenZFS commit: 21bbe7cb6
- Additional background resources:
docs/RESOURCES.md - ZFS on disk format for modern day OpenZFS: mminkus/zfs-ondiskformat
- Understanding the OpenZFS Codebase: A Guided Walkthrough for Engineers: mminkus/zfs-codebase