Skip to main content

Performing Backups

This guide covers how to create backups using rustic_core, including basic backups, incremental backups, and advanced filtering options.

Overview

Backups in rustic_core create immutable snapshots of your data. Each backup operation produces a new snapshot that efficiently stores only the data that has changed since the last backup.

Basic Backup

1
Open the repository
2
First, open your repository with indexed IDs support:
3
use rustic_core::{
    Repository, RepositoryOptions, Credentials,
    BackupOptions, PathList, SnapshotOptions
};
use rustic_backend::BackendOptions;

let backends = BackendOptions::default()
    .repository("/path/to/repo")
    .to_backends()?;

let repo_opts = RepositoryOptions::default();
let credentials = Credentials::password("my-password");

let repo = Repository::new(&repo_opts, &backends)?
    .open(&credentials)?
    .to_indexed_ids()?;
4
Create a backup
5
Specify the source path(s) and create a snapshot:
6
let backup_opts = BackupOptions::default();
let source = PathList::from_string("/data/to/backup")?.sanitize()?;
let snap = SnapshotOptions::default().to_snapshot()?;

// Create the backup
let snapshot = repo.backup(&backup_opts, &source, snap)?;
println!("Created snapshot: {}", snapshot.id);
7
Add metadata to snapshots
8
You can add tags, hostname, and description:
9
let snap = SnapshotOptions::default()
    .add_tags("important,project-x")?  
    .hostname("my-server")
    .description("Daily backup")
    .to_snapshot()?;

let snapshot = repo.backup(&backup_opts, &source, snap)?;

Backup Multiple Paths

Backup multiple directories in a single snapshot:
let paths = vec![
    "/home/user/documents",
    "/home/user/projects",
    "/etc/config"
];

let source = PathList::from_iter(paths).sanitize()?;
let snapshot = repo.backup(&backup_opts, &source, snap)?;

Incremental Backups

rustic_core automatically performs incremental backups using parent snapshots.

Using Parent Snapshots

By default, rustic_core finds a suitable parent snapshot based on hostname, paths, and labels:
let backup_opts = BackupOptions::default();
// Parent snapshot is automatically detected
let snapshot = repo.backup(&backup_opts, &source, snap)?;

Grouping Criteria

Control how parent snapshots are selected:
use rustic_core::SnapshotGroupCriterion;

let parent_opts = ParentOptions::default()
    .group_by(SnapshotGroupCriterion::from_str("host,paths,tags")?);

let backup_opts = BackupOptions::default().parent_opts(parent_opts);

Explicit Parent

Specify an explicit parent snapshot:
let parent_opts = ParentOptions::default()
    .parents(vec!["a1b2c3d4".to_string()]); // Snapshot ID

let backup_opts = BackupOptions::default().parent_opts(parent_opts);

Force Full Backup

Force a backup without using a parent (reads all files):
let parent_opts = ParentOptions::default().force(true);
let backup_opts = BackupOptions::default().parent_opts(parent_opts);

Filtering and Exclusions

See /home/daytona/workspace/source/crates/core/src/commands/backup.rs:186-199

Exclude Patterns

Exclude files matching glob patterns:
use rustic_core::Excludes;

let excludes = Excludes::default()
    .add_exclude("*.tmp")
    .add_exclude("node_modules/")
    .add_exclude(".git/");

let backup_opts = BackupOptions::default().excludes(excludes);

Exclude Files

Use exclude files (like .gitignore):
let excludes = Excludes::default()
    .add_exclude_file(".backupignore");

Size Filtering

Filter files by size:
use rustic_core::LocalSourceFilterOptions;

let filter_opts = LocalSourceFilterOptions::default()
    .glob(vec!["*.log".to_string()])
    .iglob(vec!["*.jpg".to_string()]); // Case-insensitive

let backup_opts = BackupOptions::default()
    .ignore_filter_opts(filter_opts);

Advanced Options

Skip Unchanged Snapshots

Skip creating a snapshot if nothing has changed:
let parent_opts = ParentOptions::default()
    .skip_if_unchanged(true);

let backup_opts = BackupOptions::default().parent_opts(parent_opts);

Ignore File Metadata Changes

Ignore ctime or inode changes when detecting modifications:
let parent_opts = ParentOptions::default()
    .ignore_ctime(true)   // Ignore change time
    .ignore_inode(true);  // Ignore inode number changes

Custom Backup Path

Set a custom path in the snapshot metadata:
use std::path::PathBuf;

let backup_opts = BackupOptions::default()
    .as_path(PathBuf::from("/virtual/path"));

Dry Run

Test backup without writing data:
let backup_opts = BackupOptions::default().dry_run(true);
let snapshot = repo.backup(&backup_opts, &source, snap)?;
// No data is actually written to repository

Disable Size Scanning

Skip scanning for total size (disables ETA):
let backup_opts = BackupOptions::default().no_scan(true);

Backing Up from stdin

Backup data from stdin:
// Use "-" as the source path
let source = PathList::from_string("-")?;
let backup_opts = BackupOptions::default()
    .stdin_filename("mydata.txt"); // Name for the stdin data

let snapshot = repo.backup(&backup_opts, &source, snap)?;

Backup Command Output

Backup the output of a command:
use rustic_core::CommandInput;

let source = PathList::from_string("-")?;
let backup_opts = BackupOptions::default()
    .stdin_command(CommandInput::from_str("mysqldump mydb")?)
    .stdin_filename("database.sql");

let snapshot = repo.backup(&backup_opts, &source, snap)?;

Save Options

Control how files are saved:
use rustic_core::LocalSourceSaveOptions;

let save_opts = LocalSourceSaveOptions::default()
    .save_opts(...); // Configure save behavior

let backup_opts = BackupOptions::default()
    .ignore_save_opts(save_opts);

Common Scenarios

Daily Backup Script

use rustic_core::*;

fn daily_backup() -> Result<(), Box<dyn std::error::Error>> {
    let backends = BackendOptions::default()
        .repository("/backup/repo")
        .to_backends()?;
    
    let repo = Repository::new(&RepositoryOptions::default(), &backends)?
        .open(&Credentials::from_file(".credentials"))?
        .to_indexed_ids()?;
    
    let source = PathList::from_iter(vec![
        "/home/user",
        "/etc",
    ]).sanitize()?;
    
    let excludes = Excludes::default()
        .add_exclude("**/cache/**")
        .add_exclude("**/.cache/**")
        .add_exclude("**/tmp/**");
    
    let backup_opts = BackupOptions::default()
        .excludes(excludes)
        .parent_opts(ParentOptions::default().skip_if_unchanged(true));
    
    let snap = SnapshotOptions::default()
        .add_tags("daily")?  
        .description("Automated daily backup")
        .to_snapshot()?;
    
    let snapshot = repo.backup(&backup_opts, &source, snap)?;
    println!("Backup completed: {}", snapshot.id);
    
    Ok(())
}

See Also

Build docs developers (and LLMs) love