RepoPilotOpen in app →

rustic-rs/rustic

rustic - fast, encrypted, and deduplicated backups powered by Rust

Healthy

Healthy across the board

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 1d ago
  • 20 active contributors
  • Apache-2.0 licensed
Show all 6 evidence items →
  • CI configured
  • Tests present
  • Concentrated ownership — top contributor handles 67% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/rustic-rs/rustic)](https://repopilot.app/r/rustic-rs/rustic)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/rustic-rs/rustic on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: rustic-rs/rustic

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/rustic-rs/rustic shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 1d ago
  • 20 active contributors
  • Apache-2.0 licensed
  • CI configured
  • Tests present
  • ⚠ Concentrated ownership — top contributor handles 67% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live rustic-rs/rustic repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/rustic-rs/rustic.

What it runs against: a local clone of rustic-rs/rustic — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in rustic-rs/rustic | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 31 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>rustic-rs/rustic</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of rustic-rs/rustic. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/rustic-rs/rustic.git
#   cd rustic
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of rustic-rs/rustic and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "rustic-rs/rustic(\\.git)?\\b" \\
  && ok "origin remote is rustic-rs/rustic" \\
  || miss "origin remote is not rustic-rs/rustic (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "src/bin/rustic.rs" \\
  && ok "src/bin/rustic.rs" \\
  || miss "missing critical file: src/bin/rustic.rs"
test -f "src/application.rs" \\
  && ok "src/application.rs" \\
  || miss "missing critical file: src/application.rs"
test -f "src/commands.rs" \\
  && ok "src/commands.rs" \\
  || miss "missing critical file: src/commands.rs"
test -f "src/config.rs" \\
  && ok "src/config.rs" \\
  || miss "missing critical file: src/config.rs"
test -f "Cargo.toml" \\
  && ok "Cargo.toml" \\
  || miss "missing critical file: Cargo.toml"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 31 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~1d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/rustic-rs/rustic"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

rustic is a fast, encrypted, and deduplicated backup tool written in Rust that reads and writes the restic repository format, enabling it to serve as a drop-in restic replacement. It provides encrypted backup storage with deduplication, supports multiple cloud backends (S3, B2, WebDAV, SFTP, etc.), and leverages Rust's performance and memory safety for reliable cross-platform backups on Linux, macOS, BSD, and experimental Windows support. Multi-crate Rust monorepo structure: main binary at src/bin/rustic.rs depends on rustic_core and rustic_backend libraries. Feature flags in Cargo.toml gate optional functionality (tui, prometheus, webdav, mount, opentelemetry, jq/rhai filtering). Config examples live in config/ directory with service-specific templates (config/services/). GitHub Actions workflows in .github/workflows/ orchestrate build, test, audit, and release.

👥Who it's for

Systems administrators and power users who need a performant, encrypted backup solution compatible with the restic ecosystem but want the safety and speed benefits of a Rust implementation. Contributors familiar with Rust who want to work on backup infrastructure.

🌱Maturity & risk

rustic is in beta state (version 0.11.2) with active CI/CD pipelines, comprehensive GitHub Actions workflows (audit, lint, release, cross-platform), and release automation via release-plz. However, the README explicitly warns it lacks regression tests and is not recommended for production backups yet. The codebase is actively maintained but not production-ready.

The project has a large dependency surface (multiple crates: rustic_core 0.11.0, rustic_backend 0.6.1, plus heavy ecosystem deps like tokio, ratatui, opentelemetry, axum for optional features). Beta status and lack of regression tests is a major risk. Windows support is experimental. Dependencies on optional features (mount, prometheus, webdav, tui) increase surface area for issues.

Active areas of work

Active development with release-plz automation (.github/workflows/release-plz.yml and release-plz.toml indicate automated versioning). Recent work includes cross-platform CI (cross-ci.yml), nightly testing, audit scanning, and Docker image releases. The CHANGELOG.md and cliff.toml config suggest structured release notes generation.

🚀Get running

git clone https://github.com/rustic-rs/rustic.git
cd rustic
cargo build --release
cargo run -- --help

Requires Rust 1.88.0+ (specified in Cargo.toml rust-version). Use cargo build --features default for full feature set, or cargo build --no-default-features for minimal install.

Daily commands:

cargo build --release
./target/release/rustic backup --help
./target/release/rustic init -r <repo-path>  # Initialize a backup repository
./target/release/rustic backup <path-to-backup> -r <repo-path>  # Create a backup

For development, use cargo run -- <command> or check build.sh and build-dependencies.just for build orchestration.

🗺️Map of the codebase

  • src/bin/rustic.rs — Main entry point for the CLI application; all command execution flows through here.
  • src/application.rs — Core application state and lifecycle management; handles initialization and command dispatch.
  • src/commands.rs — Command router and orchestration; defines all available CLI commands and their structure.
  • src/config.rs — Configuration loading and validation; central to understanding how rustic reads config files and CLI args.
  • Cargo.toml — Project dependencies and feature flags; essential for understanding build configuration and optional components like TUI, mounts, and allocators.
  • src/commands/backup.rs — Primary backup command implementation; demonstrates the core backup workflow and deduplication strategy.
  • src/commands/restore.rs — Restore command implementation; shows how snapshots are reconstructed and written back to storage.

🛠️How to make changes

Add a new backup-related command

  1. Create a new command module in src/commands/ (e.g., src/commands/mycommand.rs) with a struct implementing the command logic (src/commands/mycommand.rs)
  2. Add the module declaration in src/commands.rs and add a variant to the main Commands enum (src/commands.rs)
  3. Implement clap::Subcommand derive for argument parsing in your new command struct (src/commands/mycommand.rs)
  4. Add a match arm in src/application.rs to handle command execution and call your command's run method (src/application.rs)
  5. Add config options if needed in src/config.rs or create a new config submodule (src/config.rs)

Add a new TUI screen or interactive feature

  1. Create a new module in src/commands/tui/ (e.g., src/commands/tui/myscreen.rs) with state and event handlers (src/commands/tui/myscreen.rs)
  2. Implement the screen drawing logic using ratatui widgets (refer to src/commands/tui/widgets/ for custom widgets) (src/commands/tui/myscreen.rs)
  3. Register your screen in src/commands/tui.rs event loop and state machine (src/commands/tui.rs)
  4. Add navigation/transitions to your screen from other TUI screens if needed (src/commands/tui/snapshots.rs)

Extend configuration options

  1. Add new fields to the relevant config struct in src/config.rs or a submodule (src/config.rs)
  2. Add the field to config/full.toml to document the new option with examples (config/full.toml)
  3. Read and validate the config in the command that uses it (e.g., src/commands/backup.rs) (src/commands/backup.rs)
  4. Add environment variable override support (e.g., RUSTIC_FIELD) following existing patterns in src/config.rs (src/config.rs)

Add optional feature (mount, webdav, TUI, etc.)

  1. Define feature flag in Cargo.toml under [features] (Cargo.toml)
  2. Wrap implementation code with #[cfg(feature = "feature_name")] in the command module (src/commands/myfeature.rs)
  3. Conditionally add the command variant and match arm in src/commands.rs and src/application.rs (src/commands.rs)
  4. Add the feature to the default or release features in Cargo.toml if it should be included by default (Cargo.toml)

🔧Why these technologies

  • Rust + cargo — Memory-safe, fast backup tool with strong type system; enables safe concurrent I/O and encryption without garbage collection overhead
  • clap for CLI parsing — Declarative command-line argument definition with automatic help/shell completion generation
  • serde + TOML — Human-readable config format with type-safe deserialization and validation
  • ratatui for TUI — Cross-platform terminal UI framework for interactive snapshot browsing and restore wizards
  • Custom allocators (mimalloc, jemalloc) — Switchable allocators at compile-time for performance tuning in high-volume backup scenarios

⚖️Trade-offs already made

  • Content-addressable deduplication (chunk by content hash)

    • Why: Maximizes storage savings across snapshots and enables parallel backup of identical files
    • Consequence: Requires separate metadata tracking; slower on small files due to hashing overhead
  • Encrypted-at-rest with client-side keys

    • Why: End-to-end encryption with no server-side key exposure; storage backend is zero-knowledge
    • Consequence: User loses backup if password/key is forgotten; no server-side search or dedup of encrypted chunks
  • Optional TUI and WebDAV features (feature-gated)

    • Why: Reduces binary size for headless servers; users opt-in to interactive tooling
    • Consequence: Fragmented CLI experience; some workflows require compilation with specific features
  • Prune as separate command from forget

    • Why: Forget marks snapshots for removal; prune actually reclaims space—decouples logic and allows dry-run
    • Consequence: Two-step workflow; users may forget to prune and not see space savings

🚫Non-goals (don't propose these)

  • Does not implement local filesystem snapshots or copy-on-write block devices
  • Does not provide server-side deduplication or key management
  • Does not support incremental block-level backups (all snapshots are independent content hashes)
  • Does not handle RAID or multi-replica storage (delegates to backend storage provider)
  • Does not provide built-in backup scheduling (users integrate with cron/systemd timers)

🪤Traps & gotchas

Beta instability: Regression tests are explicitly missing; do not assume all features are stable. Restic format coupling: changes must maintain compatibility with restic repository format (see [design document][2] in README); breaking this breaks interop. Feature interactions: optional features like webdav, tui, and prometheus each pull in heavy transitive deps (axum, tokio, ratatui); full feature compilation is slow. Windows experimental: do not rely on Windows support for production. MSRV tight: Rust 1.88.0 is required; older toolchains will fail. Config file paths: config/ directory contains examples; actual runtime config location depends on platform (typically ~/.rustic/ or /etc/rustic/); see config examples for details.

🏗️Architecture

💡Concepts to learn

  • Content-addressed deduplication — Core to rustic's efficiency; understanding how content hashing enables sharing blocks across snapshots is essential for backup logic and bug fixes.
  • Restic repository format — rustic's entire data layer must maintain format compatibility with restic; incompatibility breaks interoperability and user recovery paths.
  • Lock-free concurrent access — A key rustic feature allowing multiple clients to safely access a repository simultaneously without blocking; implemented via atomic operations and versioning.
  • Append-only backup semantics — Default behavior ensures old backups cannot be modified, preserving immutability for compliance and disaster recovery; critical for retention policies.
  • Feature flags / conditional compilation — Cargo features (tui, webdav, prometheus, mount) gate optional functionality; understanding when to enable/disable them affects binary size, performance, and available commands.
  • Encryption at rest (AES-256-GCM) — All backup data is encrypted; understanding key derivation, nonce generation, and AEAD modes is essential for security-sensitive contributions.
  • Snapshot metadata and tags — rustic organizes backups by hostname, paths, labels, and tags; this metadata layer is used for retention policies, filtering, and restore targeting.
  • restic/restic — The upstream repository format standard that rustic reads/writes; rustic is a compatible reimplementation with performance focus.
  • rustic-rs/rustic_core — Core library extracted from rustic providing backup logic, snapshot management, and deduplication; main binary depends on this.
  • rustic-rs/rustic_backend — Backend abstraction layer supporting multiple storage targets (S3, B2, SFTP, WebDAV); decoupled from core and reusable.
  • golang-cz/rclone — Multi-backend cloud storage abstraction that rustic integrates with for unified access to 70+ cloud services.
  • matrix-org/synapse — Not directly related but useful reference: another large Rust+Python project with comprehensive CI/CD automation similar to rustic's GitHub Actions setup.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add integration tests for backup command with multiple backend types

The repo supports multiple backends (S3, B2, WebDAV, SFTP, etc.) with example configs in config/services/, but there's no visible integration test suite validating the backup command against these different backends. This would catch regressions early and validate the CLI works end-to-end with real storage backends.

  • [ ] Create tests/integration/backup_backends.rs to test backup command with mock S3, WebDAV, and local backends
  • [ ] Reference config/services/ examples and extend them for test scenarios
  • [ ] Add GitHub Actions workflow test-integration.yml to run these tests on PR
  • [ ] Validate that the backup command properly uses rustic_backend and rustic_core features for each backend type

Add missing documentation for config files in docs/ directory

The repo has extensive example configs in config/ (full.toml, hooks.toml, par2.toml, services/*.toml) but docs/Readme.md is minimal. New users cannot understand which config options exist, what hooks.toml enables, or how to use par2.toml for parity recovery.

  • [ ] Create docs/CONFIGURATION.md documenting all top-level config sections from config/full.toml
  • [ ] Create docs/HOOKS.md explaining the hook system with examples from config/hooks.toml
  • [ ] Create docs/SERVICES.md explaining each service backend (B2, S3, SFTP, WebDAV) with config snippets from config/services/
  • [ ] Link these new docs from README.md and docs/Readme.md

Add feature-gated unit tests for optional features (webdav, tui, opentelemetry)

The Cargo.toml defines multiple optional features (webdav, tui, opentelemetry, prometheus, mount) but there's no visible test coverage validating these features compile and work correctly. This risks feature bit-rot and silent breakage when dependencies update.

  • [ ] Create tests/features/webdav.rs with tests gated by #[cfg(feature = "webdav")] validating dav-server and axum integration
  • [ ] Create tests/features/tui.rs testing ratatui and crossterm integration for terminal UI
  • [ ] Create tests/features/observability.rs testing prometheus and opentelemetry exports
  • [ ] Add .cargo/audit.toml or GitHub Action to run cargo test with each feature individually (--features=tui, --features=webdav, etc.)

🌿Good first issues

  • Add regression tests for core backup/restore workflows: the README warns regression tests are missing; start with a simple test case that creates a backup, snapshots it, and verifies restore integrity using the example configs in config/.
  • Document Windows support status: create a Windows-specific troubleshooting guide under docs/ since the README mentions Windows is experimental but provides no details on known limitations or setup steps.
  • Expand config examples for missing backends: config/services/ has templates for S3, B2, SFTP, WebDAV, but lacks examples for Rclone or other cloud services; add one with inline comments explaining each option.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • e03e638 — fix(scripts): portable bash shebang and prevented array expansions (#1753) (Turmaxx)
  • bf3c820 — fix: use indicatif-log-bridge to avoid breaking progress bar on log (#1747) (LucaCiucci)
  • 8e134b6 — build(deps): bump thin-vec from 0.2.14 to 0.2.16 (#1732) (dependabot[bot])
  • 9c3bab5 — build(deps): bump rustls-webpki from 0.103.10 to 0.103.13 (#1745) (dependabot[bot])
  • 5c8dc89 — feat: Add warning about profile-substitute without profiles (#1743) (aawsome)
  • 73d7620 — fix: respect config-supplied backup(.snapshot).init (#1742) (jullanggit)
  • b5588a0 — feat(commands): Add version command (#1738) (Turmaxx)
  • d594e03 — chore: release v0.11.2 (#1700) (rustic-release-plz[bot])
  • 724b64f — chore: update dependencies (#1723) (aawsome)
  • fed326b — chore(deps): unpin and update self_update (#1699) (GideonBear)

🔒Security observations

The rustic backup tool demonstrates generally good security practices with proper licensing, dependency management via Cargo, and security audit configurations. However, there are notable concerns: (1) The Docker build process lacks binary verification, creating supply chain risks; (2) The containerized application runs as root without privilege separation; (3) Edition 2024 declaration may indicate configuration issues; (4) Broad default feature enablement increases attack surface. The codebase shows no obvious injection vulnerabilities or hardcoded secrets in the provided samples. Recommendations focus on strengthening the build/deployment pipeline and tightening default configurations.

  • Medium · Incomplete Dependency Declaration in Cargo.toml — Cargo.toml - webdav dependencies section. The dav-server dependency declaration appears truncated in the provided Cargo.toml snippet, with the line ending incomplete at 'optional ='. This could indicate a parsing issue or incomplete configuration that may affect dependency resolution and security auditing. Fix: Verify the complete dependency declaration is properly formatted. Ensure all optional dependencies are fully specified with their versions and features.
  • Medium · Dockerfile Uses wget Without Verification — Dockerfile - builder stage. The Dockerfile downloads prebuilt binaries from GitHub releases using wget without any cryptographic verification (no checksums, signatures, or integrity checks). This creates a risk of supply chain attacks if the GitHub release is compromised. Fix: Implement binary verification by: (1) downloading and verifying GPG signatures, (2) comparing SHA256 checksums from a trusted source, or (3) building from source instead of downloading prebuilt binaries.
  • Medium · Docker Image Uses 'scratch' Base Without User Context — Dockerfile - final stage. The final Docker image is built from 'scratch' with no user isolation. While /etc_files/passwd and /etc_files/group are created, the application runs as root (UID 0), which violates the principle of least privilege. Fix: Create a non-root user in the passwd/group files and configure the image to run as that user. Use USER directive in Dockerfile to drop privileges before executing the application.
  • Low · Edition 2024 May Not Be Stable — Cargo.toml - edition field. The Cargo.toml specifies 'edition = "2024"', which appears to be a future Rust edition. This may indicate a test/development configuration or incorrect entry that could cause compatibility issues. Fix: Verify the edition is intentional. If this is a production crate, use a stable edition (2021 or earlier). If 2024 is intended as a beta feature, document this explicitly and monitor Rust announcements.
  • Low · Broad Feature Enablement in Default Features — Cargo.toml - default features. The default features include multiple optional dependencies (jq, prometheus, opentelemetry, tui, webdav) which increases the attack surface. Each additional dependency introduces potential vulnerabilities. Fix: Consider making optional features opt-in rather than default. Document why each feature is included by default. Regularly audit transitive dependencies using 'cargo audit' and 'cargo tree'.
  • Low · Configuration Files in Version Control — config/ directory. Multiple example configuration files (config/*.toml) are included in the repository. While these are examples, they may contain sensitive template patterns that could guide attackers on what credentials or configurations to target. Fix: Ensure example configurations do not contain actual credentials or sensitive patterns. Add clear warnings in comments that these are examples. Consider using placeholder syntax like <YOUR_API_KEY> instead of realistic examples.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · rustic-rs/rustic — RepoPilot