Skip to main content
FileSync package icon

FileSync

v5.0.0Latest Stable
Any Framework

Sync/back up local files to a directory or Azure Blob storage, driven by a .filesync config (JSON or YAML) or inline options. Commands: sync, clean, watch, init; with dry-run, confirmation prompts, glob filters, and a preloaded REPL.

Published
Jun 23, 2026
4mo ago
Total Downloads
1.9K
1,863

Install

dotnet add package FileSync --version 5.0.0

No framework information available.

README

FileSync

A small command-line tool to sync / back up a local folder to another directory or to Azure Blob Storage, driven by a .filesync.yaml config file and/or inline options.

Built on .NET 10.

What's new in v5!

Total rewritten CLI layer, built on top of the beautiful CommandLine.EasyBuilder -- which sits thin on top of System.CommandLine. The formerly CLI wiring layer went from a nightmare to ever want to change anything, and easily 85% what would make us afraid to ever touch this app, to now: a handful of BEAUTIFULLY simple Cmd classes, with simple command and arg names and descriptions. Check out CommandLine.EasyBuilder, it makes CLI creation a breeze. --help is generated straight from these classes β€” so the documentation can't drift from the code.

Thanks to the one and only Claude Opus for knocking this migration out of the park! I simply would not have had the time to do this migration otherwise (not enough reward to do a major work like this).

Now in color

Run any command and you'll see it β€” the output got a real upgrade (built on the excellent Spectre.Console). Before a single byte is written, a tidy pre-op report frames exactly what's about to happen: source, destination, a per-target badge ([dir], [azure]), eligible file counts, and the active filters/excludes. Then the live work log is lightly color-coded β€” green for added/synced, red for trouble. The preloaded-REPL config banner is styled too.

And it degrades gracefully. Pass --no-color, set NO_COLOR, or pipe the output anywhere and you get clean plain text β€” piped logs stay byte-for-byte identical. Want just the log without the report? --quiet / -q. And expected errors now surface as a one-line Error: … instead of a stack trace (set FILESYNC_DEBUG to get the full trace when you actually want it).

Breaking changes β€” and the why

The changes are breaking, but deliberate:

  1. Conventions. When I first wrote FileSync I was new to CLI customs; v5 standardizes the command and flag names to match how mainstream tools behave.
  2. The core is unchanged. sync is still sync. A few things just moved to where they fit better β€” e.g. the old check command (preview a sync without writing) is now simply sync --dry-run.
  3. The config is de-emphasized. The .filesync file used to be a catch-all β€” it even encoded which operation to run (watch: / sync: booleans) and confirmation settings. Those now live on the CLI, so a config is just what to sync: source, destination, filters, target. (Old configs still load β€” legacy keys are recognized, retired ones ignored.)
  4. REPL is opt-in. It used to always stay running as a REPL. Now it acts like a normal CLI: give a command and it runs once; run with no command (or --repl) to get a REPL; and pointing it at a bare config β€” filesync some.filesync β€” opens a REPL with that config preloaded.

The sync engine is essentially untouched β€” just a bug fix or two (e.g. a dry-run or canceled sync no longer leaves an empty destination folder behind).

Migrating from earlier versions

Was Now
filesync check <config> filesync sync <config> --dry-run
filesync new <path> filesync init <path> (--format yaml|json)
clean … --yes / -y clean … --noconfirm / -y
config watch: true / sync: true run the watch / sync command
config promptOnDelete clean confirms by default; --noconfirm skips

Existing .filesync files keep working β€” unknown or retired keys are simply ignored. Or run filesync migrate <old.filesync> to auto-convert a legacy config into a clean, notes-annotated .filesync.yaml (your original is left untouched).

.filesync config file now defaults to use *.filesync.yaml or *.filesync.json

Install

dotnet pack -c Release          # produces ./nupkg/FileSync.<version>.nupkg
dotnet tool install --global --add-source ./nupkg FileSync

The filesync command is then available globally (dotnet tool update --global FileSync to upgrade, dotnet tool uninstall --global FileSync to remove).

Usage

filesync <command> [config] [options]
Command Does
sync Copy/upload changed source files to the destination. --dry-run previews; --confirm asks first.
clean Delete destination files no longer in the source (orphans). --dry-run lists them; confirms by default (--noconfirm/-y to skip).
watch Watch the source and auto-sync changes until Ctrl+C.
init Scaffold a sample .filesync. --type azure, --format (yaml or json; default yaml).
migrate Convert an old .filesync to the new format β€” writes a new *.filesync.yaml (never overwrites) with inline migration notes. --format.

[config] is a .filesync file, or a directory containing one. If omitted (and no --src is given), a config in the current directory is used.

Running modes

  • One-shot (default): filesync sync ./deploy.filesync
  • REPL: run with no arguments, or pass --repl β€” you get a prompt to issue commands repeatedly until exit.
  • Bare config β†’ preloaded REPL: filesync ./deploy.filesync (a config path, no command) loads it and drops into the REPL with it preloaded; a bare sync / clean / watch then acts on that config.

Common options

Shared by sync, clean, and watch:

Option Meaning
-s, --src Source directory (inline mode)
-d, --dest Destination directory, or cloud sub-path/prefix after the container
-t, --type directory (default), azure, ftp*, amazon*
-f, --filter Include glob, repeatable: --filter "**/*.js" --filter "**/*.css"
-x, --exclude Exclude glob, repeatable
-c, --container Cloud container name
--account-name / --account-key Azure account name / key
--creds / --creds-path Azure connection string inline / from a file
--since Ignore files older than e.g. 1h, 10m, 2.5d
-r, --root Root that relative inline paths resolve against (default: current dir)
-p, --parallel Parallel uploads β€” on by default (--parallel false, or config parallel: false, to disable)
-v, --verbose Verbose logging
-q, --quiet Suppress the pre-op report (the work log still prints)
--no-color Disable colored output (also honors NO_COLOR and piped/redirected output)

* ftp and amazon (S3) are recognized targets but not yet implemented (they throw if used) β€” directory and azure are the working targets.

The .filesync file

A config just says what to sync β€” source, destination, filters, target. Write it in YAML, named .filesync.yaml (JSON works too β€” .filesync.json β€” if you'd rather). Either is auto-discovered when you point FileSync at a directory, and filesync init scaffolds one for you. Relative src / dest / credsPath resolve against the config file's own folder (or --root).

The simplest config backs a folder up to another directory. directory is the default target, so no type is needed β€” and omitting filters means "everything":

src: ./photos
dest: D:/backup/photos

Narrow it with include / exclude globs β€” here, just the built JS and CSS, minus sourcemaps:

src: ./dist
dest: ./out
filters:
  - "**/*.js"
  - "**/*.css"
exclude:
  - "**/*.map"

Upload a built site to Azure Blob storage:

type: azure
src: ./dist
dest: v1                 # sub-path / prefix after the container (optional)
container: my-site
accountName: myaccount
credsPath: ./key.txt     # a file holding the key β€” or inline `creds` / `accountKey`

Run several syncs from one file by listing them under syncs:. Each entry takes the same fields; since (skip files untouched for 1h / 10m / 2.5d) is per-entry, and an optional profile-level root sets a shared base for relative paths:

syncs:
  - src: ./docs
    dest: ./backup/docs

  - type: azure
    src: ./dist
    dest: v1
    container: my-site
    accountName: myaccount
    credsPath: ./key.txt
    since: 12h           # this entry only: skip files untouched for 12h+

Fields: type (directory Β· azure; ftp / amazon are scaffolded only), src, dest, filters, exclude, container, accountName, accountKey, creds, credsPath, since, parallel β€” plus profile-level root and syncs. JSON configs additionally allow // comments and trailing commas, and anywhere a list is expected a single string works too.

Examples

No config β€” just point at a source and destination:

filesync sync --src ./photos --dest D:/backup/photos          # local β†’ local
filesync sync -s ./dist -d ./out -f "**/*.js" -f "**/*.css"   # only JS + CSS
filesync sync -s ./dist -d ./out -x "**/*.map"                # everything except sourcemaps

Preview, confirm, then commit:

filesync sync ./deploy.filesync --dry-run     # show what would change, write nothing
filesync sync ./deploy.filesync --confirm     # show the plan, then ask before writing
filesync sync ./deploy.filesync               # just sync

Keep a destination live while you work, or clean up orphans:

filesync watch ./deploy.filesync              # re-sync on every change until Ctrl+C
filesync clean ./deploy.filesync --dry-run    # list destination files no longer in source
filesync clean ./deploy.filesync              # delete them (asks first; -y to skip)

Azure, entirely inline (no config file):

filesync sync -s ./dist -t azure -d v1 \
  -c my-site --account-name myaccount --creds-path ./key.txt

Recent files only, scaffold, migrate, explore:

filesync sync ./deploy.filesync --since 2h    # skip files untouched for 2h+
filesync init --type azure                    # write a starter .filesync.yaml (Azure flavor)
filesync migrate ./old.filesync               # convert a legacy config β†’ .filesync.yaml
filesync ./deploy.filesync                     # bare config, no command β†’ preloaded REPL

Changes from Previous Version

No structural changes between v4.0.5 and v5.0.0.

Adoption Assessment

Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.

No target framework metadata is available. Confirm compatibility in a representative project before standardising on this package.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.