How to Extract a Single File from a Borg Backup Archive Without Recreating the Entire Directory Tree

Extracting a Single File from a Borg Archive Without Recreating the Entire Directory Tree

When a backup archive grows to several terabytes, restoring a single configuration file or a database dump can feel like pulling a needle from a haystack. Borg’s default extract command rebuilds the whole directory tree, which is wasteful when you only need one file. The following guide shows how to pull a single file efficiently, keeps metadata intact, and keeps your system secure.


Why Pull a Single File?

  • Time‑saving – Restoring a 1 GB file from a 50 GB archive can take minutes if the whole tree is rebuilt.
  • Disk‑space conservation – You avoid creating thousands of empty directories.
  • Audit and forensic work – Quickly inspect a file without touching the rest of the backup.
  • Recovery scripts – Automate extraction of log files or config snippets during incident response.

Quick Borg Reference

CommandPurposeTypical flags
borg listShow archive contents--format
borg extractRestore files--strip-components, --no-same-permissions
borg catOutput a file’s contents--format
borg exportStream a file to stdout--format

All commands assume a local repository. For remote repos, prepend ssh://user@host:/path/to/repo or use the --remote-path option.


1. Locate the File Inside the Archive

Before extracting, you need the exact path as stored in the archive. Use borg list with a format that shows the full path:

borg list /mnt/backup::my‑archive \
  --format="{path}\n" | grep -i "myapp/config.yaml"

If the archive contains multiple matching files, add --sort or --limit to narrow the output. The result will look like:

home/user/projects/myapp/config.yaml

Keep this path; it will be the argument for the extraction commands.


2. Extracting With borg extract

The simplest way to pull a file while avoiding the rest of the tree is to use --strip-components. This option removes a specified number of leading path components before writing the file.

borg extract /mnt/backup::my‑archive \
  --strip-components=3 \
  home/user/projects/myapp/config.yaml

How It Works

  • home/user/projects/myapp/config.yamlmyapp/config.yaml after stripping three components (home, user, projects).
  • The file is written to the current working directory (or a path you specify with --target).

Trade‑offs

BenefitDrawback
Fast – only the file’s data blocks are read.Path loss – you lose the original directory context unless you reconstruct it manually.
Low disk usage – no extra directories.Permissions – the file inherits the current user’s UID/GID unless you use --same-permissions.

If you need the original ownership and permissions, add --same-permissions and ensure the target directory is owned by the same UID/GID as the backup.


3. Using borg cat for Raw Extraction

When you only need the file’s contents (e.g., to pipe into another tool), borg cat is the most lightweight option:

borg cat /mnt/backup::my‑archive \
  --format="{path}\n" \
  home/user/projects/myapp/config.yaml > /tmp/config.yaml

borg cat streams the file directly to stdout, so you can redirect it anywhere. This is ideal for:

  • Feeding a file into openssl for decryption.
  • Piping into jq for JSON manipulation.
  • Feeding into sed or awk for quick edits.

Caveat: borg cat does not preserve file metadata. If you need ownership or timestamps, use extract.


4. Streaming with borg export

borg export is a newer command that streams a file or directory to stdout, preserving metadata in the stream. It’s handy when you want to pipe the file into another program that accepts a file descriptor.

borg export /mnt/backup::my‑archive \
  home/user/projects/myapp/config.yaml | \
  gzip > /tmp/config.yaml.gz

The exported stream contains the file’s mode, timestamps, and extended attributes. The receiving side can use borg import to restore the file with metadata intact.


5. Working With Remote Repositories

When the repository is on a remote host, the same commands apply, but you must specify the remote path. For example:

borg extract ssh://backupuser@backup.example.com:/srv/backup::my‑archive \
  --strip-components=3 \
  home/user/projects/myapp/config.yaml

If the remote host runs a non‑standard borg binary, use --remote-path:

borg extract --remote-path=/usr/local/bin/borg \
  ssh://backupuser@backup.example.com:/srv/backup::my‑archive \
  --strip-components=3 \
  home/user/projects/myapp/config.yaml

Security note: The SSH key used for the connection should have the no-pty and command="borg serve" restrictions in authorized_keys to prevent arbitrary command execution. See the Borg documentation for a recommended authorized_keys snippet.


6. Preserving Permissions and Ownership

If you need the file to retain its original UID/GID, use --same-permissions and --same-owner (the latter requires root). Example:

sudo borg extract /mnt/backup::my‑archive \
  --strip-components=3 \
  --same-permissions \
  --same-owner \
  home/user/projects/myapp/config.yaml

Running as root is necessary because changing ownership to a non‑existing UID/GID is not permitted otherwise. If the target system has the same user accounts, the file will be restored with the correct ownership.


7. Security Considerations

IssueMitigation
Encrypted archivesAlways use Borg’s built‑in encryption (borg create --encryption=repokey). The key is stored in ~/.config/borg/keys. Keep the key file on a separate, encrypted device.
Key exposureUse borg key export to rotate keys. Store the key in a password‑protected keyring (e.g., pass).
Remote accessRestrict SSH access to the backup user. Use authorized_keys with command="borg serve" and no-pty.


See also