Andrew Mercer
on this page

tar

Format: .tar (plus .tar.gz, .tar.bz2, .tar.xz, .tar.zst, …) · Type: archiver · First released: 1979, Version 7 Unix

tar (tape archive) bundles files and their metadata into a single stream. It doesn't compress by itself; it hands the stream to a compressor such as gzip, bzip2, xz or zstd. GNU tar is the standard on Linux. macOS, the BSDs and Windows ship bsdtar (libarchive), which uses mostly the same flags and reads more formats.

Archive formats: the original V7 format, POSIX ustar (1988), GNU extensions, and POSIX pax (2001), which removes old limits on path length, file size and metadata.

Operation modes (pick one)

Flag Long form Meaning
c --create Create
x --extract Extract
t --list List contents
r --append Append files (uncompressed archives only)
u --update Append newer versions (uncompressed only)
A --concatenate Append another tar archive
d --diff Compare archive to filesystem
--delete Remove members (uncompressed only)

Common modifiers

Flag Meaning
f FILE Archive file (- = stdin/stdout). Must be followed directly by the filename.
v Verbose (vv for a long listing)
C DIR Change to DIR first
z gzip
j bzip2
J xz
--zstd zstd (GNU tar 1.31+)
--lzip, --lzma, --lzop, Z lzip, legacy LZMA, lzop, compress
a, --auto-compress Pick the compressor from the archive extension when creating
I CMD, --use-compress-program=CMD Use any compressor command, with options

Creating archives

# Plain tar
tar cvf archive.tar src_dir/

# Compressed tarballs
tar czvf archive.tar.gz    src_dir/      # gzip
tar cjvf archive.tar.bz2   src_dir/      # bzip2
tar cJvf archive.tar.xz    src_dir/      # xz
tar --zstd -cvf archive.tar.zst src_dir/ # zstd

# Let tar pick from the extension
tar caf archive.tar.zst src_dir/

# Full control over the compressor (threads, level, long mode)
tar -I 'zstd -T0 -19 --long=31' -cf archive.tar.zst src_dir/
tar -I 'xz -T0 -9' -cf archive.tar.xz src_dir/
tar -I pigz -cf archive.tar.gz src_dir/

In bundled style, letter order mostly doesn't matter (czvf == zcvf == cvzf) except that f must come last, because the next word is taken as the filename. tar cfz archive.tar.gz dir creates an archive literally named z. Dashed options (-c -z -f archive.tar.gz) avoid the problem.

Extracting

GNU tar and bsdtar auto-detect compression when reading, so the compression flag is optional:

tar xvf archive.tar.gz            # works for .gz, .bz2, .xz, .zst, .lz, .Z ...
tar xvf archive.tar.xz -C /opt    # extract into /opt (must exist)

Explicit forms still work:

tar xzvf archive.tar.gz
tar xjvf archive.tar.bz2
tar xJvf archive.tar.xz
tar --zstd -xvf archive.tar.zst

Anything after the archive name is a list of members to extract, not a destination. Use -C for the destination:

tar xvf archive.tar.gz src_dir/config.yaml        # one member
tar xvf archive.tar.gz --wildcards '*.conf'       # by pattern
tar xvf archive.tar.gz -C /tmp/restore src_dir/   # member into a directory
tar xOf archive.tar.gz src_dir/config.yaml        # member to stdout

Listing

tar tvf archive.tar.gz            # auto-detects compression
tar tzvf archive.tar.gz           # explicit gzip
tar tjvf archive.tar.bz2          # explicit bzip2
tar tJvf archive.tar.xz           # explicit xz
tar tf archive.tar.gz | head      # names only; check for a single top-level dir

Using the wrong flag (for example tar tjvf file.tar.gz) fails, so either match the flag to the compressor or leave it out.

Excluding and filtering

tar czf backup.tar.gz \
  --exclude='*.log' \
  --exclude='node_modules' \
  --exclude-vcs \
  --exclude-caches \
  project/

tar czf backup.tar.gz -X exclude-list.txt project/   # patterns from a file
tar czf backup.tar.gz -T file-list.txt               # files to include, from a file
find . -name '*.rs' -print0 | tar czf src.tar.gz --null -T -
tar czf recent.tar.gz --newer-mtime='7 days ago' project/

--exclude-vcs skips .git, .svn and friends. --exclude-caches skips directories with a CACHEDIR.TAG file (Cargo's target/ has one). Put --exclude options before the paths for portability.

Controlling paths

# Archive the contents of a dir without the dir as a prefix
tar czf site.tar.gz -C /var/www/site .

# Strip leading components on extract
tar xzf release.tar.gz --strip-components=1 -C /opt/app

# Rename on the fly (sed-style)
tar czf out.tar.gz --transform 's,^build,myapp-1.2.0,' build/

GNU tar strips the leading / from absolute paths when creating ("Removing leading /' from member names"). That's a safety feature;-P` disables it, which you almost never want.

Preserving metadata

tar --acls --xattrs --selinux -cpzf full.tar.gz /srv/data
tar --acls --xattrs --selinux -xpzf full.tar.gz -C /
tar --numeric-owner -czf data.tar.gz /srv/data
tar --one-file-system -czf root.tar.gz /
tar -S -czf vm.tar.gz disk.img             # handle sparse files efficiently
  • -p preserves permissions on extract (default as root).
  • As root, tar restores original ownership; as a normal user, files belong to you. --no-same-owner forces the latter even as root (useful in containers).
  • --numeric-owner matters when restoring onto a system whose names map to different UIDs/GIDs.
  • --one-file-system stops at mount points, avoiding /proc, network mounts and so on.
  • -S / --sparse stores holes in sparse files instead of gigabytes of zeroes.

Incremental backups (GNU tar)

# Level 0 (full)
tar --listed-incremental=snap.snar -czf full.tar.gz /data

# Incrementals (copy the snapshot file first to keep the level-0 state)
cp snap.snar snap-1.snar
tar --listed-incremental=snap-1.snar -czf incr-1.tar.gz /data

# Restore: full, then each incremental in order
tar --listed-incremental=/dev/null -xzf full.tar.gz -C /
tar --listed-incremental=/dev/null -xzf incr-1.tar.gz -C /

For serious backups, restic, borg, or kopia add deduplication, encryption, and pruning, but this works with nothing but tar.

Appending, comparing, verifying

These only work on uncompressed .tar files:

tar rvf archive.tar newfile          # append
tar uvf archive.tar src_dir/         # append changed files
tar --delete -f archive.tar oldfile  # remove a member
tar df archive.tar                   # diff archive vs filesystem
tar cWf archive.tar dir/             # verify after writing

Formats and long paths

tar --format=posix -cf archive.tar dir/   # pax: no path/size limits, full metadata
tar --format=ustar -cf archive.tar dir/   # maximum compatibility, 255-char paths, 8 GiB files

GNU tar's default gnu format handles long names too; choose posix when other tools need to read the archive.

Reproducible tarballs

For byte-identical build artifacts:

tar --sort=name \
    --mtime='2026-01-01 00:00Z' \
    --owner=0 --group=0 --numeric-owner \
    --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime \
    -cf - dir/ | gzip -n > dir.tar.gz

Encrypted tarballs

tar has no encryption. Pipe the compressed stream through age, gpg, or openssl:

tar cf - dir/ | zstd -T0 | age -p > dir.tar.zst.age
age -d dir.tar.zst.age | zstd -d | tar xf -

See encryption for all the options and why openssl des3 should be avoided.

See also