restic — API Surface#

API types#

CLI only. restic is a single-binary command-line tool. It exposes no HTTP server, no gRPC service, and no public Go library API. All packages live under internal/ — intentionally unexported. The only external-facing surface is:

  • The CLI (cobra commands + pflag flags)
  • The REST server protocol (restic is a REST client; it talks to a separate rest-server binary)
  • Exit codes (documented and meaningful)
  • JSON output mode (machine-readable structured stdout for most commands)

CLI#

Framework#

  • Framework: github.com/spf13/cobra + github.com/spf13/pflag
  • Registration pattern: Each command lives in its own file (cmd_backup.go, etc.) and exposes a constructor newBackupCommand(globalOptions *global.Options) *cobra.Command. All constructors are called in main.go:newRootCommand() via a single cmd.AddCommand(...) block.
  • Flag pattern: Every command’s options live in a dedicated <Command>Options struct with an AddFlags(f *pflag.FlagSet) method. Global flags are registered via globalOptions.AddFlags(cmd.PersistentFlags()) and are persistent (inherited by all subcommands).
  • Three optional commands are conditionally registered: mount (FUSE, Linux/macOS only), debug (debug build tag), self-update (separate build tag). Each has a disabled stub (cmd_*_disabled.go) that registers a helpful error message on unsupported platforms.

Command structure#

Top-level commands (28 total)#

Core backup/restore:

CommandUsageDescription
backupbackup [flags] [FILE/DIR]...Create a new backup snapshot
restorerestore [flags] snapshotIDRestore a snapshot to target directory
snapshotssnapshots [flags] [snapshotID...]List all snapshots
lsls [flags] snapshotID [dir...]List files in a snapshot
diffdiff [flags] snapshotID snapshotIDShow differences between two snapshots
dumpdump [flags] snapshotID fileDump file contents from a snapshot to stdout
findfind [flags] PATTERN...Find files in snapshots matching patterns
mountmount [flags] mountpointMount snapshots as a FUSE filesystem (Linux/macOS)

Repository management:

CommandUsageDescription
initinitInitialize a new repository
checkcheck [flags]Verify repository integrity
pruneprune [flags]Remove unreferenced data from repository
forgetforget [flags] [snapshot ID]...Remove snapshots per retention policy
copycopy [flags] [snapshotID...]Copy snapshots to another repository
rewriterewrite [flags] [snapshotID...]Modify snapshots (exclude paths)
tagtag [flags] [snapshotID...]Modify tags of snapshots
unlockunlockRemove stale repository locks
recoverrecover [flags]Find and save unattached snapshot trees
migratemigrate [flags] [name]...Run repository format migrations

Key management:

CommandSubcommandDescription
keylistList encryption keys
keyaddAdd a new encryption key
keyremove [ID]Remove an encryption key
keypasswdChange the password for a key

Repair commands:

CommandSubcommandDescription
repairindex [flags]Repair repository index
repairpacks [packIDs...]Repair pack files
repairsnapshots [flags] [snapshot ID]...Repair snapshot metadata

Utility/informational:

CommandUsageDescription
catcat [flags] [type] [ID]Dump raw object (masterkey, config, pack, blob, snapshot, index, key, lock, tree)
listlist [flags] [type]List repository objects by type
statsstats [flags] [snapshot ID]...Scan repository for statistics
cachecacheOperate on local cache
generategenerate [flags]Generate man pages / shell completion
optionsoptionsList all available extended options
featuresfeaturesList feature flags and their states
versionversionPrint version information
self-updateself-update [flags]Update restic binary in place
debugdebug dump / debug examineInternal debug commands (debug builds only)

Deprecated command (kept for compat):

  • rebuild-index — alias for repair index

Global flags (persistent — all commands)#

All defined in internal/global/global.go:Options.AddFlags():

FlagShortEnv varPurpose
--repo-rRESTIC_REPOSITORYRepository location (URL or path)
--repository-fileRESTIC_REPOSITORY_FILEFile containing repository location
--password-file-pRESTIC_PASSWORD_FILEFile containing repository password
--password-commandRESTIC_PASSWORD_COMMANDShell command to obtain password
--key-hintRESTIC_KEY_HINTKey ID to try first
--quiet-qSuppress progress output
--verbose-vIncrease verbosity (repeatable: -vv)
--jsonOutput in JSON format
--no-lockSkip repository locking (read-only safe)
--no-cacheDisable local cache
--cache-dirCustom cache directory
--cleanup-cacheAuto-remove old cache entries
--cacertRESTIC_CACERTRoot CA certificate files
--tls-client-certRESTIC_TLS_CLIENT_CERTTLS client certificate
--insecure-tlsSkip TLS verification (insecure)
--insecure-no-passwordUse empty password (insecure)
--limit-uploadUpload rate limit (KiB/s)
--limit-downloadDownload rate limit (KiB/s)
--option / -oExtended backend options (k=v)
--http-user-agentCustom HTTP User-Agent
--no-extra-verifySkip pre-upload data verification
--compressionCompression level (off, auto, max)
--pack-sizeRESTIC_PACK_SIZETarget pack file size (MiB)

Notable command flags#

backup — key flags:

  • --parent snapshot — use specific parent for delta comparison
  • --force / -f — force full re-read (ignore parent)
  • --exclude PATTERN / --include PATTERN — glob-based file filtering
  • --exclude-if-present filename[:header] — directory exclusion by marker file
  • --exclude-caches — auto-exclude CACHEDIR.TAG directories
  • --exclude-larger-than SIZE — size-based exclusion
  • --one-file-system / -x — no cross-filesystem traversal
  • --stdin — backup from stdin
  • --stdin-from-command — backup stdout of a command
  • --files-from FILE — read target list from file
  • --tag TAG — attach tags to snapshot
  • --host / -H — override hostname in snapshot metadata
  • --time TIMESTAMP — override backup timestamp
  • --with-atime — include access time
  • --ignore-inode / --ignore-ctime — change detection tuning
  • --dry-run / -n — show what would be done
  • --read-concurrency N — parallel file readers
  • --skip-if-unchanged — skip if snapshot is identical to parent
  • --use-fs-snapshot — use VSS (Windows) / APFS snapshots

forget — retention policy flags:

  • --keep-last N / -l — keep N most recent (or unlimited)
  • --keep-hourly N / -H — keep N hourly
  • --keep-daily N / -d — keep N daily
  • --keep-weekly N / -w — keep N weekly
  • --keep-monthly N / -m — keep N monthly
  • --keep-yearly N / -y — keep N yearly
  • --keep-within DURATION — keep all within duration (e.g. 1y5m7d2h)
  • --keep-within-hourly/daily/weekly/monthly/yearly DURATION — keep granular within duration
  • --keep-tag TAGLIST — keep snapshots with matching tags
  • --group-by HOST,PATHS,TAGS / -g — grouping key for policy application (default: host,paths)
  • --unsafe-allow-remove-all — required safety flag to delete all snapshots
  • --prune — automatically run prune after removing snapshots
  • --dry-run / -n — preview only

restore — key flags:

  • --target / -t — target directory
  • --include/--exclude PATTERN — partial restore
  • --host / --path / --tag — snapshot selection filters
  • --verify — verify restored files
  • --delete — delete extra files not in snapshot
  • --overwrite POLICY — overwrite policy (always, if-changed, if-newer, never)

copy — key flags:

  • --repo2 / -2 / RESTIC_REPOSITORY2 — destination repository
  • --password-file2 / RESTIC_PASSWORD_FILE2 — destination password
  • Applies the standard snapshot filter flags

Flag binding pattern#

Every backend scheme supports --option key=value extended options (collected by global.Options). Examples:

  • s3.bucket-lookup, s3.unsafe-anonymous-auth, s3.enable-restore
  • sftp.command, sftp.args
  • rest.connections

These are parsed by internal/options and applied to driver config structs via options.ApplyEnvironment.

Output modes#

Human-readable (default): Progress bars, tables, human-friendly sizes.

JSON (--json global flag): Structured JSON output for machine consumption. Each command emits typed JSON objects with a message_type discriminator field. Supported by: backup, check, copy, diff, find, forget, ls, prune, restore, snapshots, stats. Error output also becomes structured JSON ({"message_type":"exit_error","code":N,"message":"..."}).

Exit codes#

Documented and stable — designed for scripting:

CodeMeaning
0Success
1Generic error
3Incomplete operation (e.g. source data error during backup, failed snapshot removal)
10No repository found
11Repository already locked
12Wrong password / no valid key found
130SIGINT / context cancelled

REST server protocol (restic as HTTP client)#

restic is not an HTTP server. However, its rest backend implements a well-defined HTTP protocol for talking to a compatible server (e.g. the rest-server project). Understanding this matters because third-party servers must implement these endpoints.

URL structure (from layout_rest.go and rest.go):

POST   {base}/                          -- create repository (version negotiation)
HEAD   {base}/{type}/{id}               -- check object existence
GET    {base}/{type}/{id}               -- read full object
GET    {base}/{type}/{id} (Range header) -- read partial object
POST   {base}/{type}/{id}               -- write object
DELETE {base}/{type}/{id}               -- delete object
GET    {base}/{type}/                   -- list objects of type (v1: JSON array, v2: NDJSON)
GET    {base}/config                    -- read repository config

Type paths:

  • data/ — pack files (encrypted data)
  • snapshots/ — snapshot metadata
  • index/ — index files
  • locks/ — lock files
  • keys/ — encryption key files
  • config — repository configuration (no directory)

Protocol versions: v1 (list returns JSON array) and v2 (list returns NDJSON, one file per line). Version negotiated at Create time via query parameter.


Plugin / Extension system#

Backend extension point#

The primary extension point is the backend registry (internal/backend/location.Registry). Adding a storage backend requires:

  1. Implement backend.Backend interface
  2. Implement location.Factory interface with Scheme() string, ParseConfig(s string) (Config, error), Open(ctx, cfg, rt, errLog) (Backend, error), Create(ctx, cfg, rt, errLog) (Backend, error)
  3. Register via registry.Register(factory)

All 9 built-in backends (azure, b2, gs, local, rclone, rest, s3, sftp, swift) use this mechanism. Registered at startup in backend/all/all.go.

The decorator wrappers (cache, retry, logger, sema, limiter, dryrun) are composed at startup in internal/global/global.go:wrapBackend() — they are not runtime-pluggable, but the backend.Unwrapper interface and backend.AsBackend[T]() generic function allow introspection through the decorator chain.

Feature flags extension point#

internal/feature provides a simple flag registry. Flags are defined at compile time in registry.go, but their enabled/disabled state is configurable at runtime via the RESTIC_FEATURES environment variable. This allows gradual rollout of new behavior (Alpha → Beta → Stable → (removal)).

Current flags (as of analysis):

  • backend-error-redesign (Beta) — new HTTP timeout/error handling
  • deprecate-legacy-index (Stable) — drop support for 0.1.0 index format
  • deprecate-s3-legacy-layout (Stable) — drop support for pre-0.7.0 S3 layout
  • device-id-for-hardlinks (Alpha) — reduced metadata churn for btrfs
  • explicit-s3-anonymous-auth (Stable) — require explicit anonymous S3 opt-in
  • safe-forget-keep-tags (Stable) — safety check for --keep-tag with nonexistent tags
  • s3-restore (Alpha) — restore from S3 cold storage

rclone backend as a meta-extension#

The rclone backend (internal/backend/rclone) is unique: it shells out to the rclone binary, passing arguments via a private REST-like protocol over rclone serve restic. This effectively gives restic access to every storage provider that rclone supports (~40+) without native implementation.


Library API (if applicable)#

None. All packages are under internal/. restic explicitly does not offer a public Go API for embedding. The design rationale (visible from the architecture) is that restic manages encryption keys, repository locking, and data integrity — exposing these as a library would require callers to handle these invariants correctly. The CLI is the only supported interface.

The closest thing to a library interface is the backend.Backend interface in internal/backend, but it is internal-only.


Notable API design observations#

  1. Global-options-as-configuration-carrier: global.Options is passed by pointer from main() through cobra’s PersistentPreRunE to every command. Commands receive it as a constructor argument rather than via a global variable. This is explicit dependency passing within a CLI framework that could easily have used package-level globals.

  2. Consistent snapshot filter flags: Commands that operate on snapshots (forget, restore, copy, rewrite, ls, snapshots, tag, find) share a common SnapshotFilter struct with identical --host, --path, --tag flags, wired via initMultiSnapshotFilter(). This is a rare example of deliberate API consistency across CLI subcommands.

  3. --dry-run is pervasive: backup, forget, prune, rewrite, and restore (via --verify) all support dry-run modes. This is intentional for a backup tool where destructive operations need safe preview.

  4. Structured JSON output as a first-class API: The --json flag transforms restic from a human-readable CLI into a structured data source. The JSON schema is stable enough that tools like resticprofile and Prometheus exporters build on it. Each command’s JSON output uses typed message_type discriminators — a clean approach to multiplexing different event types on a single stream.

  5. Extended options (-o key=value) as an escape hatch: Backend-specific options that don’t warrant global flags are routed through --option. The options command lists all available options. This prevents global flag explosion while still documenting all tunable parameters.

  6. No config file by design: There is no ~/.resticrc or restic.yaml. All configuration must be explicit on the CLI or via environment variables. This is a principled choice for a security tool — configuration should be auditable and visible at the point of invocation.