Skip to content
shellmap

Create a tar archive from a directory

Bundle a directory tree into a single compressed file — for backups, transport, version-snapshot, and the `dist/` artifact step in a build.

How to create a tar archive from a directory in each shell

Bashunix
tar czf out.tar.gz dir/

`c` create, `z` gzip, `f FILE` archive name. `cJf` for xz (smaller, slower); `cjf` for bzip2; `cf` for uncompressed. `--exclude="*.log"` skips matching paths. `-C /parent dir` changes working dir before archiving (cleaner archive root).

Zshunix
tar czf out.tar.gz dir/
Fishunix
tar czf out.tar.gz dir/
PowerShellwindows
tar.exe -czf out.tar.gz dir/

Win10+ bundled tar.exe. For pwsh-native (no tar.exe): `Compress-Archive dir/ out.zip` (ZIP ONLY — tar not supported). For tar, must use `tar.exe`, `7z a -ttar out.tar dir/`, or .NET 7+ `System.Formats.Tar` API.

cmd.exewindows
tar.exe -czf out.tar.gz dir

Win10 1803+. Note: cmd doesn't expand globs the way bash does (`dir/*` won't work in cmd — pass `dir` and tar walks recursively).

Equivalents listed for Bash, Zsh, Fish, PowerShell, cmd.exe.

Gotchas & notes

  • **Choose compression based on use case**: `gzip` (`.tar.gz`/`.tgz`) — default, ubiquitous, mid-range compression, fast. `xz` (`.tar.xz`) — best compression (~30% smaller than gzip), much slower CPU, default for many Linux source tarballs. `bzip2` (`.tar.bz2`) — slightly smaller than gzip, slower, no good reason to use over xz in 2026. `zstd` (`.tar.zst`) — modern: same compression as xz at gzip speed, requires `tar --use-compress-program=zstd` or `tar -I zstd` (GNU tar with `-I` is 2014+; not on older Centos). `zstd` is the cost-effective default for new pipelines; gzip for max compatibility.
  • **`-C /parent dir` for clean archive root** — without it, `tar czf out.tar.gz /home/user/project` records the FULL PATH (`home/user/project/...`) inside the archive, so extraction recreates the deep path. With `tar czf out.tar.gz -C /home/user project`, the archive root is `project/` (clean, portable). This matters for `npm publish`-style workflows where the archive's top-level dir should be the project name. Same idea with `--transform="s,^project/,foo/,"` (GNU tar) to RENAME the root inside the archive.
  • **`--exclude=` patterns**: `--exclude="*.log"` glob match. `--exclude-vcs` (skip `.git`, `.svn`, `.hg` — convenient for "release tarball"). `--exclude-from=FILE` reads patterns from file (one per line). MULTIPLE `--exclude` allowed. Ordering: place `--exclude` BEFORE the source path on the cmdline (or use a config file) — `tar czf out.tar.gz dir/ --exclude="*.log"` works in GNU tar but BSD tar is stricter about order. ALWAYS verify the archive with `tar tf` after creation to confirm exclusions worked.
  • **Permissions, ownership, sparse files**: tar PRESERVES permissions (0644, etc.), owner UID/GID, mtime by default. If extracting on a different system, the UIDs may not exist — `tar xf archive.tar --no-same-owner` extracts as the current user (the default for non-root extract). `tar xf archive.tar --no-same-permissions` ignores stored permissions. For BACKUPS that need to ROUND-TRIP through tar without permission loss, run as root on both ends. Sparse files (databases, VM images): GNU tar `--sparse` detects holes and stores them efficiently — disabled by default because it scans every byte for zeros.
  • **Reproducible builds**: a tar archive's bytes vary even if the contents are identical — file ORDER, mtime, owner/group, and compression metadata all differ across runs. For bit-identical archives: `tar --sort=name --mtime="@0" --owner=0 --group=0 --numeric-owner -cf - dir/ | gzip -n > out.tar.gz`. `--sort=name` (GNU 1.28+) sorts entries deterministically; `--mtime="@0"` sets all mtimes to epoch; `--owner=0 --group=0 --numeric-owner` removes user info; `gzip -n` omits the filename + timestamp in the gzip header. Used by Debian source packages, Bazel, Nix, OCI image builders.

Related commands

Related tasks