ZFS Confused by snapshots

I'm new to ZFS, and today I decided to try to learn how to create a snapshot of my zroot pool. I tried following the handbook... which is not exactly strong on exposition.

So I used the following command:

> ls .zfs/snapshot

Nothing was present. I then did:

> sudo zfs snapshot zroot@08-10-2025

and several minutes later, I got the following:

> ls -l .zfs/snapshot
total 9
drwxr-xr-x 20 root wheel 25 Jul 30 01:32 2025-07-31-00:00:52-0

which, I'm not sure what I was expecting but it wasn't a ten day old file. Assuming that I had done something wrong, I read the handbook section again and then issued:

> sudo zfs snapshot zroot/ROOT@2025-08-10

and I still get

ls -l .zfs/snapshot
total 9
drwxr-xr-x 20 root wheel 25 Jul 30 01:32 2025-07-31-00:00:52-0

Is there a more beginner-friendly intro to ZFS than the handbook that anyone can recommend?
 
Where are you when you are checking for snapshots, whats the path? zroot dataset should be mounted to /zroot directory by default.
 
In fact, zroot/ROOT/default dataset is mounted to /, so you are snapshotting a different dataset using different mountpoint. To test, go to /zroot then check .zfs directory.

You can take recursive snapshot of a ZFS pool, i.e. zroot. This way it will snapshot all the child datasets of it, can be called whole backup.

# zfs snapshot -r zroot@today

I can also share my script that i use for taking quick recursive zfs snapshots that can you add comments and date.

Code:
#!/bin/csh

set date = `date +%F-%H:%M`

if ( "$#argv" > 0 ) then
    set pool = "$argv[1]"
else
    echo "Pool to take snapshot from: "
    set pool = "$<"
endif

if ( "$pool" == "" ) then
    echo "No pools given."
    exit 1
endif

set checkpool = "zfs list -H $pool >& /dev/null"
eval $checkpool
if ( "$status" != 0 ) then
    echo "Couldn't found pool: $pool"
    exit 1
endif

if ( "$#argv" >= 2 ) then
    set comment = "$argv[2]"
    set isComment = 1
    set fixedComment = `echo "$comment" | sed 's/ /-/g'`
    set c = ":$fixedComment"
else
    echo "Comment to add to the snapshot name: "
    set comment = "$<"
    if ( "$comment" == "" ) then
        set isComment = 0
    else
        set isComment = 1
        set fixedComment = `echo "$comment" | sed 's/ /-/g'`
        set c = ":$fixedComment"
    endif
endif

if ( ! "$?isComment" ) then
    set isComment = 0
endif

echo "Will operate on pool: $pool"
echo "Date is: $date"

if ( "$isComment" != 0 ) then
    if ( "$fixedComment" == "" ) then
        set takesnap = "zfs snapshot -r $pool@$date"
    else
        echo "Comment is: $fixedComment"
        set takesnap = "zfs snapshot -r $pool@$date$c"
    endif
else
    set takesnap = "zfs snapshot -r $pool@$date"
endif
eval $takesnap
if ( "$status" != 0 ) then
    echo "Error taking snapshot of $pool"
    exit 1
else
    echo "Snapshot is taken: done!"
    if ( "$isComment" != 0 ) then
        if ( "$fixedComment" == "" ) then
            set showsnap = "zfs list -H -t snap $pool@$date"
        else
            set showsnap = "zfs list -H -t snap $pool@$date$c"
        endif
    else
        set showsnap = "zfs list -H -t snap $pool@$date"
    endif
    eval $showsnap
endif

exit 0

Usage:
Code:
# takesnap zroot "hello there"
Will operate on pool: zroot
Date is: 2025-08-10-23:53
Comment is: hello-there
Snapshot is taken: done!
zroot@2025-08-10-23:53:hello-there      0B      -       96K     -

% zfs list -t snap -r zroot | grep hello-there
zroot@2025-08-10-23:53:hello-there                                         0B      -    96K  -
zroot/ROOT@2025-08-10-23:53:hello-there                                    0B      -    96K  -
zroot/ROOT/default@2025-08-10-23:53:hello-there                          280K      -  5.59G  -
zroot/ccache@2025-08-10-23:53:hello-there                                  0B      -  18.2G  -
zroot/ccachei386@2025-08-10-23:53:hello-there                              0B      -  20.7M  -
zroot/poudriere@2025-08-10-23:53:hello-there                               0B      -   112K  -
zroot/poudriere/data@2025-08-10-23:53:hello-there                          0B      -  4.41G  -
zroot/poudriere/jails@2025-08-10-23:53:hello-there                         0B      -    96K  -
zroot/poudriere/jails/143amd64@2025-08-10-23:53:hello-there                0B      -  2.29G  -
zroot/poudriere/jails/143i386@2025-08-10-23:53:hello-there                 0B      -  1.96G  -
zroot/tmp@2025-08-10-23:53:hello-there                                     0B      -   954M  -
zroot/usr@2025-08-10-23:53:hello-there                                     0B      -    96K  -
zroot/usr/home@2025-08-10-23:53:hello-there                              200K      -  12.6G  -
zroot/usr/obj@2025-08-10-23:53:hello-there                                 0B      -    96K  -
zroot/usr/ports@2025-08-10-23:53:hello-there                               0B      -  1.70G  -
zroot/usr/src@2025-08-10-23:53:hello-there                                 0B      -  1.17G  -
zroot/var@2025-08-10-23:53:hello-there                                     0B      -    96K  -
zroot/var/audit@2025-08-10-23:53:hello-there                               0B      -    96K  -
zroot/var/crash@2025-08-10-23:53:hello-there                               0B      -  1.06G  -
zroot/var/log@2025-08-10-23:53:hello-there                                 0B      -  1.09M  -
zroot/var/mail@2025-08-10-23:53:hello-there                                0B      -   152K  -
zroot/var/tmp@2025-08-10-23:53:hello-there
 
In fact, zroot/ROOT/default dataset is mounted to /, so you are snapshotting a different dataset using different mountpoint. To test, go to /zroot then check .zfs directory.

You can take recursive snapshot of a ZFS pool, i.e. zroot. This way it will snapshot all the child datasets of it, can be called whole backup.

# zfs snapshot -r zroot@today

I can also share my script that i use for taking quick recursive zfs snapshots that can you add comments and date.

Code:
#!/bin/csh

set date = `date +%F-%H:%M`

if ( "$#argv" > 0 ) then
    set pool = "$argv[1]"
else
    echo "Pool to take snapshot from: "
    set pool = "$<"
endif

if ( "$pool" == "" ) then
    echo "No pools given."
    exit 1
endif

set checkpool = "zfs list -H $pool >& /dev/null"
eval $checkpool
if ( "$status" != 0 ) then
    echo "Couldn't found pool: $pool"
    exit 1
endif

if ( "$#argv" >= 2 ) then
    set comment = "$argv[2]"
    set isComment = 1
    set fixedComment = `echo "$comment" | sed 's/ /-/g'`
    set c = ":$fixedComment"
else
    echo "Comment to add to the snapshot name: "
    set comment = "$<"
    if ( "$comment" == "" ) then
        set isComment = 0
    else
        set isComment = 1
        set fixedComment = `echo "$comment" | sed 's/ /-/g'`
        set c = ":$fixedComment"
    endif
endif

if ( ! "$?isComment" ) then
    set isComment = 0
endif

echo "Will operate on pool: $pool"
echo "Date is: $date"

if ( "$isComment" != 0 ) then
    if ( "$fixedComment" == "" ) then
        set takesnap = "zfs snapshot -r $pool@$date"
    else
        echo "Comment is: $fixedComment"
        set takesnap = "zfs snapshot -r $pool@$date$c"
    endif
else
    set takesnap = "zfs snapshot -r $pool@$date"
endif
eval $takesnap
if ( "$status" != 0 ) then
    echo "Error taking snapshot of $pool"
    exit 1
else
    echo "Snapshot is taken: done!"
    if ( "$isComment" != 0 ) then
        if ( "$fixedComment" == "" ) then
            set showsnap = "zfs list -H -t snap $pool@$date"
        else
            set showsnap = "zfs list -H -t snap $pool@$date$c"
        endif
    else
        set showsnap = "zfs list -H -t snap $pool@$date"
    endif
    eval $showsnap
endif

exit 0

Usage:
Code:
# takesnap zroot "hello there"
Will operate on pool: zroot
Date is: 2025-08-10-23:53
Comment is: hello-there
Snapshot is taken: done!
zroot@2025-08-10-23:53:hello-there      0B      -       96K     -

What is the difference between a recursive snapshot and a regular snapshot in this case? Does a regular snapshot not descend into other zfs mount points?
 
What is the difference between a recursive snapshot and a regular snapshot in this case? Does a regular snapshot not descend into other zfs mount points?
A recursive snapshot takes childs of the specified ZFS dataset too, this means you can backup your whole ZFS datasets, all of them by specifying a ZFS "root" dataset like zroot. Non-recursive one just takes snapshot of one dataset which means it will backup the directory where that ZFS dataset is mounted to.

For example, i use my script then send it (as a file) to my hard drive for backup.

# zfs send -R -v zroot@2025-06-29-19:34:today > /storage/zroot@2025-06-29-19:34:today
 
Is there a more beginner-friendly intro to ZFS than the handbook that anyone can recommend?
I'm sure you will find many tutorials, How-Tos etc. on the internet.
But frankly in my eyes not of much use, if only read.

My point, as silly as it sounds:
You don't need to gather more knowledge. You simply just need to grasp the idea of how it works.

All you need for the normal, everyday usage and maintenence already is in the man pages zfs(8) and zpool(8), and the handbook.
Anything else would be long elaborated explaining text nobody actually reads, still theoretical, while you still have, or get even more questions.

I always recommend to have a "laboratory rat" 🐀, especially for ZFS:
Get some simple, used hardware (what you may find in the attic, or get second hand on a garage sale for a few bucks), tower-case was best, 4GB RAM are sufficient.
Two criteria: It doesn't bother you, when something breaks. And FreeBSD runs on it. (basic "vanilla"; no need for a GUI. you will do everything in the shell anyway; the cheapest graphics adapter will do, if any. just get some monitor attached that shows text.)
Place a couple of (old, but working) drives into it, and just play with it.

Believe me:
One saturday afternoon with your "rat" is worth way more 💡, than slaving days over dozens of textpages 🥵.
Experience can only be gained practically.

Brownie point:
Later the "rat" may become really useful. For me it was the start for my first NAS. :cool:

Tip:
Before you consider to start your first real ZFS pool to store actual valuable data, also learn about partition labels, and use those. Also no rocket science; just one more option in your partition creation, but unpayable value in the long term.
 
Every filesystem has its own set of snapshots, so when you ls .zfs/snapshot you are looking at just the snapshots for the mountpoint of that filesystem. Assume you snapshotted zroot, look in the snapshot dir and you won't see anything about home, tmp, var, etc.
 
Root pool? Root on ZFS?
search for "Boot Environments". Plenty of stuff there.
Michael W Lucas books on ZFS (with Allan Jude) if they don't make sense then something else is wrong.l

My opinion, based solely on my experience, don't equate "snapshots" and "boot environments". Yes they share some things but they are not the same.
Simplistically:
A boot environment is a r/w clone of a snapshot of a ZFS dataset.

man bectl is your friend.
 
Back
Top