All apps · 0 apps
ArrowLoop
Docker app from junkerderprovinz's Repository
Overview
Readme
View on GitHub
Two-way file sync that shows you the plan before it moves anything.
ArrowLoop keeps two folders in step, say a NAS share and a laptop, or a phone and a WebDAV cloud. It remembers what both sides last agreed on, lists every change before a run, and stops rather than delete more than it should.
[!IMPORTANT] Android testers wanted. Google Play only lists an app from a new developer account after at least 12 testers have kept it installed for 14 days. If you have an Android phone:
- Join the tester group.
- Open the test page and tap Become a tester.
- Install ArrowLoop from Google Play and keep it for 14 days. Using it for real helps most, and anything that goes wrong is welcome as an issue.
Always downloads the latest build
A one-knight job: I build it, keep it running, work through the issues and add what people ask for, until nothing is missing. It is free, with no accounts, no telemetry, no ads and no paid tier. No asterisk anywhere. Nothing readable ever leaves your own walls. Forged on evenings and weekends, with heart and stubbornness.
If it has earned a place on your server or computer, toss a coin to your knight: it helps cover the costs and keeps the project alive. It also makes this knight's heart beat a little faster. Three ways below, whichever suits you.
Table of Contents
- What it looks like
- What it does
- How it compares
- Getting started
- Documentation
- How AI is used here
- Support this project
1. What it looks like
The container's web interface, in any browser on your network
The same interface as a desktop app: every copy, deletion and conflict of the next run, before anything moves
The Android app, with the engine running on the phone
2. What it does
- Two-way, with a memory. A state database per job tells a new file from a deleted one, so nothing deleted comes back and nothing new disappears. How it decides
- A plan before every run. The preview lists every copy, deletion and conflict. Untick a row and that file stays exactly as it is. The interface
- Brakes instead of surprises. Deletions go to a trash, a run that would delete too much or finds a side suddenly empty stops, and a crash at any step can be picked up again. Safety
- Over 60 clouds and servers. Every rclone backend is built in: SMB, SFTP, S3, WebDAV, Nextcloud, OneDrive, Google Drive and the rest. Configuring a job
- Runs on its own. Schedules, real-time watching, notifications and a run log that writes down every run. Configuring a job
- Wherever you need it. A Docker container for your server or Unraid, a desktop app for Windows, macOS and Linux, and an Android app that runs the engine on the phone. Installing
3. How it compares
GoodSync is the tool ArrowLoop was built to replace. FreeFileSync, Syncovery and SyncBack work the same way, a job you run or schedule, and are desktop programs first. Syncthing and Resilio Sync keep folders identical between devices in real time, with nothing to review before it happens. Unison and rclone bisync are two-way sync for the command line. ArrowLoop takes GoodSync's way of working and rclone's reach, runs as a container or a desktop app, and keeps a record of what both sides last agreed on.
| ArrowLoop | GoodSync | FreeFileSync | Syncthing | Resilio | bisync | Unison | Syncovery | SyncBack | |
|---|---|---|---|---|---|---|---|---|---|
| Every change shown before the run, single ones can be dropped | ✅ | ✅ | ✅ | ❌ | ❓ | ❌ | ✅ | ✅ | ✅ |
| Brake on a run that deletes too much | ✅ | ⚠️ | ⚠️ | ❌ | ❓ | ✅ | ⚠️ | ✅ | ⚠️ |
| An empty or unmounted side is refused | ✅ | ⚠️ | ⚠️ | ✅ | ⚠️ | ✅ | ✅ | ✅ | ⚠️ |
| Deletions go to a trash by default | ✅ | ✅ | ✅ | ⚠️ | ✅ | ⚠️ | ⚠️ | ✅ | ⚠️ |
| An edit on both sides keeps both versions by itself | ✅ | ⚠️ | ⚠️ | ✅ | ⚠️ | ✅ | ⚠️ | ⚠️ | ❌ |
| Cloud and server targets without a mount | ✅ | ✅ | ⚠️ | ❌ | ❌ | ✅ | ⚠️ | ✅ | ✅ |
| Encryption at the destination | ✅ | ⚠️ | ❌ | ⚠️ | ✅ | ✅ | ❌ | ✅ | ✅ |
| Sends only the changed part of a file | ❌ | ⚠️ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ⚠️ |
| Copies files another program holds open | ⚠️ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
| Built-in schedule | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ⚠️ | ✅ | ⚠️ |
| Real-time watching | ✅ | ✅ | ⚠️ | ✅ | ✅ | ❌ | ✅ | ⚠️ | ✅ |
| Scripts before and after a run | ✅ | ✅ | ⚠️ | ❌ | ❓ | ❌ | ❌ | ✅ | ✅ |
| Notification when a run fails | ✅ | ✅ | ⚠️ | ⚠️ | ⚠️ | ❌ | ❌ | ✅ | ✅ |
| Device to device over the internet, no port forwarding | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Official container image | ✅ | ❌ | ❌ | ✅ | ⚠️ | ✅ | ❌ | ❌ | ❌ |
| Web interface | ✅ | ⚠️ | ❌ | ✅ | ⚠️ | ❌ | ❌ | ⚠️ | ❌ |
| Desktop app | ✅ | ✅ | ✅ | ⚠️ | ✅ | ❌ | ✅ | ✅ | ✅ |
| Windows, macOS and Linux | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Android | ✅ | ✅ | ❌ | ⚠️ | ✅ | ⚠️ | ❌ | ❌ | ⚠️ |
| iOS | ❌ | ✅ | ❌ | ⚠️ | ✅ | ❌ | ❌ | ❌ | ❌ |
| No account and no vendor relay | ✅ | ❌ | ✅ | ⚠️ | ⚠️ | ✅ | ✅ | ✅ | ✅ |
| Open source | ✅ | ❌ | ⚠️ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ |
| Free, with every feature | ✅ | ❌ | ⚠️ | ✅ | ⚠️ | ✅ | ✅ | ❌ | ⚠️ |
| Past 1.0 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
✅ yes · ⚠️ with a catch: off by default, a paid edition, one platform only or a community build · ❌ no · ❓ undocumented. Checked against each project's own documentation in September 2026.
ArrowLoop has no relay of its own. To sync between two places over the internet, put both machines in one private network, as Installing describes.
4. Getting started
On a server, one container is enough:
docker run -d --name arrowloop -p 8422:8422 \
-v /path/to/config:/config \
-v /path/to/data:/data \
junkerderprovinz/arrowloop:latest
Then open port 8422 in a browser and add your first job. On Unraid, install it from Community Applications instead. The desktop and Android apps are the download buttons above. Passwords, reverse proxies and updates are in the installation guide.
5. Documentation
The documentation has the details this page leaves out:
- Installing: container, Unraid, desktop, Android and the single binary
- Configuring a job: every field of the job file, schedules, watching and notifications
- The interface: the preview, editing jobs, history, conflicts and the trash
- Command line: sync, jobs, web, daemon and service
- How it decides: the decision table, renames, case and Unicode
- Safety: the trash, the brakes, half-written files and crashes
- How it compares: against GoodSync, FreeFileSync, Syncthing, rclone bisync and others
- How it is tested: the convergence test, broken guards and CI on three systems
- When something goes wrong: refused runs, files that keep copying and a container that restarts
6. How AI is used here
One knight builds this, and AI is one of the tools I work with, the same way I work with an editor or a compiler. It helps me write code and documentation and it checks my work, and that saves me a good many evenings. It does not make the decisions, though. I read and understand everything before it ships, and if something here breaks, that is on me and not on the tool.
You do not have to take my word for it. The code is open and every release note is written by hand. The issue tracker shows how problems actually get handled, including the ones I got wrong the first time. If you find something that is not right, open an issue and I will look at it.
7. Support this project
Questions? Check the support thread. Bugs, ideas or feature requests? Please open a GitHub issue.
A one-knight job: I build it, keep it running, work through the issues and add what people ask for, until nothing is missing. It is free, with no accounts, no telemetry, no ads and no paid tier. No asterisk anywhere. Nothing readable ever leaves your own walls. Forged on evenings and weekends, with heart and stubbornness.
If it has earned a place on your server or computer, toss a coin to your knight: it helps cover the costs and keeps the project alive. It also makes this knight's heart beat a little faster. Three ways below, whichever suits you.
Reporting something that went wrong is worth as much. A two-way sync meets filesystems, network shares and timing that no test suite can reach on its own, and the bugs that matter here are the quiet ones. If a run did something you did not expect, open an issue with the run's own log line: it names the job, the file and the reason.
Categories
Download Statistics
Related apps
Explore more like this
Explore allLinks
Details
junkerderprovinz/arrowloop:latestRuntime arguments
- Web UI
http://[IP]:[PORT:8422]/- Network
bridge- Shell
bash- Privileged
- false
- Extra Params
--restart unless-stopped --hostname=arrowloop
Template configuration
The port the interface listens on. Until a password is set under Settings, Security, anyone who can reach it can start a sync that deletes files, so do not forward it from the internet.
- Target
- 8422
- Default
- 8422
- Value
- 8422
Holds arrowloop.json, one state database per job and the run log. This is the directory that must survive the container: without the state databases every job forgets what the two sides agreed on and treats every file as new.
- Target
- /config
- Default
- /mnt/user/appdata/arrowloop
- Value
- /mnt/user/appdata/arrowloop
The shares you want to synchronise. Point job paths at subfolders of this, for example /data/Photos. Mount it read-write: a two-way job writes to both sides by definition.
- Target
- /data
- Default
- /mnt/user
- Value
- /mnt/user
Optional. The password is normally set in the interface, under Settings, Security, which also offers two-factor authentication and passkeys. A hash here wins over that password and cannot be changed from the interface, which makes it the way back in after a forgotten one: open this container's console, run: arrowloop hash-password, type the password twice and paste the line it prints here. Neither lives in arrowloop.json, because that file can be downloaded and restored from inside the interface.
- Target
- ARROWLOOP_PASSWORD_HASH
Used for the schedules. A cron expression means nothing until the container agrees with you about what time it is.
- Target
- TZ
- Default
- Europe/Berlin
- Value
- Europe/Berlin
Where the interface binds inside the container. Leave this alone unless you know why you are changing it: outside a container the program defaults to loopback, and the container overrides that because loopback inside a container means nobody can reach it.
- Target
- ARROWLOOP_ADDR
- Default
- 0.0.0.0:8422
- Value
- 0.0.0.0:8422
The umask for everything this container writes. It runs as root, so with the usual 022 every copied file would land as 0644 root:root and every folder as 0755 root:root, which you can read over SMB and not change. An Unraid share is 0777 nobody:users, and 000 makes what ArrowLoop writes match it. The field must not be left empty: a blank template field overrides the image default rather than falling back to it. Set 022 to get restrictive permissions back.
- Target
- ARROWLOOP_UMASK
- Default
- 000
- Value
- 000
