How FlyingFiles works
This page is for the curious, and for administrators who want to know what the app does with files, passwords and the network before they install it.
At a glance
FlyingFiles is a native app for macOS, Windows and Linux. It runs only on your computer.
There's no intermediary server and no account. Files go directly between your computer, your disks and your servers, and settings and the files of paired computers — directly between those computers on your local network.
The
nci.plwebsite is used to download the app for macOS and Linux and to check for updates — at startup (you can turn this off) and when you ask. The Windows version is delivered and updated by Microsoft Store.
flowchart LR
subgraph PC["Your computer"]
APP["FlyingFiles"]
DISK["Disks, USB drives,<br/>network shares"]
KEY["Keychain /<br/>Credential Manager"]
TERM["System programs<br/>Terminal, FFmpeg,<br/>disc burning"]
end
SRV["Your servers<br/>FTP · FTPS · SFTP"]
PEER["Your paired computers<br/>on the local network"]
NCI["nci.pl<br/>download and updates<br/>for macOS and Linux"]
STORE["Microsoft Store<br/>Windows installation and updates"]
APP <--> DISK
APP <--> KEY
APP --> TERM
APP <--> SRV
APP <-. "TLS, after pairing" .-> PEER
APP -. "at startup and on request" .-> NCI
STORE -. "Windows" .-> APP
How the app is built
FlyingFiles is written in C# on .NET 10, with an Avalonia 12 user interface. The same code runs on all three systems; system-specific code is kept separate, in one place.
The app consists of three layers:
| Layer | Responsible for |
|---|---|
| Core | file systems (disk, archives), copying and moving, conflict scanning, archives, viewing and editing files of any size, Markdown, search, comparison, statistics, .ffignore rules, minifying files, FFmpeg commands, settings, settings synchronization and the .ffsync file, translations |
| Network | FTP and FTPS (FluentFTP library), SFTP (SSH.NET), reading and saving passwords in the system store, pairing computers and local network connections (settings and files of paired computers) |
| App | windows and panels (MVVM pattern), keyboard and custom shortcuts, drag and drop, system integration: Trash, Finder and File Explorer, apps associated with files, Terminal, FFmpeg, disc burning, formatting volumes, installation and updates |
Compiled to native code
The app is compiled ahead of time (Native AOT) into an executable for a specific processor. As a result:
you don't need to install .NET,
the app starts in a fraction of a second,
it uses less memory than an app with an interpreter.
An interface that doesn't freeze
Every disk and network operation runs in the background, and the interface only shows the progress. Even listing a folder on a hung network share doesn't block the window. Every operation that can take a while has a progress window and a working Cancel button.
Viewing (F3) and editing (F4) read a text file of up to 4 MB in full. Larger text and every binary file are read in pieces — only what's on the screen — so a file of several gigabytes on a disk opens instantly; such a file from a server (with a progress window) or from an archive is first copied to a temporary file. Line numbers and search are worked out in the background, and saving a file on a disk without changing its length overwrites only the changed bytes, in place.
One model for every location
The local disk, an archive, an FTP server, an SFTP server and the drives of a paired computer share a common file system interface in the app: listing, reading, writing, creating folders, deleting, renaming. The panel, copying, preview, search and comparison use only this interface. That's why:
copying works in every combination: disk → server, server → archive, server → server;
an archive behaves like a folder — the app extracts it to a private temporary folder and packs the changes back in when you leave it;
search and statistics work the same way on a disk, in an archive and on a server.
How copying works
.ffignorerules — items covered by the source and destination rules are filtered out.Destination check — you can't copy an item onto itself or a folder into its own subfolder, even when the same location is written differently: through a symbolic link, in different letter case or — on Windows — through a network drive letter. On a disk, the app compares the files' identity in the file system, not just the text of the path, so a move “onto itself” won't delete the only copy of a file.
Scan — in a single pass, the app collects the file list, the total number of bytes and the conflicts. With servers, it remembers the listings of destination folders so that it doesn't ask the server about each file separately.
Conflict decision — a dialog with a choice: overwrite all, overwrite older, skip duplicates, cancel.
Copying in 256 KB chunks, with progress:
moving within one disk is a rename — instant;
writing to a disk goes to a temporary file next to the destination, which replaces the destination file only at the end, so an interruption doesn't leave half a file behind;
moving a symbolic link to a folder never empties the folder it points to;
an error in one file doesn't stop the whole operation — the file goes on the list of failed items, with the reason.
When it's finished — optional cleanup of macOS metadata files, refreshing the panels, a summary, the list of failed items and an entry in the transfer log.
With servers
Retrying after a timeout and reconnecting after a dropped connection, returning to the same folder.
Completeness check — after an error, the app compares the size of the file on the server. It treats a complete file as done, and when the state can't be determined, it doesn't retry blindly, so that it doesn't overwrite a good copy.
SHA-256 verification (optional) — the checksum of the source file is compared with the checksum of the copy. On SFTP, the app tries to compute the checksum on the server (
sha256sum,shasum,openssl), and when the account doesn't allow that, it reads the copy back.Cancellation — a half-uploaded file is deleted from the server, and a download doesn't leave junk on the disk.
Minifying files before upload
The Minify files checkbox in the Confirm Changes window works inside the app, on your computer — with no external tool and no online service:
the app reads a PHP file from the source, removes comments, blank lines, indentation and unnecessary spaces from the code, and writes the result straight to the destination — on a disk as atomically as an ordinary copy, on a server as an ordinary upload;
the source file stays untouched, and HTML outside the PHP tags, strings and heredoc blocks pass through byte for byte;
a file the app isn't sure about (e.g. one with the short
<?tag) and a file larger than 32 MB go through unchanged, and the reason goes to the transfer log.
Drag and drop
Drag and drop uses the system's drag-and-drop mechanism — the same one Finder, File Explorer and other apps use.
Dropping in a panel starts the same process as F5 or F6:
.ffignorerules, the destination check, the scan, conflicts and the progress window.Entries from FTP/SFTP servers and from archives travel in a format that doesn't leave the app, so other apps can't see them. They can be dropped only in the panels of the window they come from.
Files on a disk also travel as ordinary system files, so Finder, File Explorer, the desktop and other apps see them like any other files and copy or move them by their own rules. On Windows, FlyingFiles offers them for copying: File Explorer copies them when no key is held and moves them only with Shift.
To files dragged in from another app, FlyingFiles always reports a copy, so that app never deletes the originals itself. A move, if you choose one, is done by FlyingFiles, just as with F6.
How burning a disc works
FlyingFiles has no burner driver of its own. The disc is burned by the tool the system provides: on macOS drutil (the same one Finder uses), on Windows IMAPI — the burning feature built into Windows — and on Linux xorriso. The app prepares the data, keeps an eye on the space and reads the progress from the tool's output.
Image estimate — from the file list, the app works out how much the disc image will take: whole 2048-byte sectors for every file, folders and names in several file systems (ISO 9660, Joliet, UDF), and a space map that grows with the image. The same estimate drives the disc template bar.
Disc check — once more before writing: whether the drive still holds the same disc and whether it has enough space.
Exact image — the system tool builds the image and gives its size to the sector; when it doesn't fit, writing doesn't start.
Writing with a progress bar, speed and a log.
Verification (optional, on by default) — the burned data is read back from the disc and compared with the image.
Closing the disc and ejecting it.
On Windows, a blank BD-R doesn't go through the usual IMAPI path, which always formats it with a spare area (unless you turn the spare area on in the settings): the app builds the image with the IMAPI tool and writes it to the disc sector by sector, and when verifying, it compares every sector with the image. That way the same disc holds as much on Windows as on macOS and Linux. None of this leaves your computer.
How video conversion works
FlyingFiles doesn't encode videos itself, and FFmpeg isn't included in its packages. The app uses FFmpeg, a free program installed on your system, and runs it as a separate process.
Finding FFmpeg — first the path from the settings (the FFmpeg program field on the Preview and video tab), then the folders in
PATH, and finally the usual installation locations: Homebrew and MacPorts on macOS; winget, Chocolatey, Scoop andC:\ffmpeg\binon Windows;/usr/bin,/usr/local/binand/snap/binon Linux. When it's missing, the app shows how to install it.Describing the recording —
ffprobe, which usually comes with FFmpeg, gives the resolution, duration, codecs and audio. Without it, the app knows only the duration and resolution from the header of MP4 and MOV files.Available encoders — the app asks FFmpeg what it can encode (
ffmpeg -encoders) and offers only that. Hardware encoding appears only after a successful test on a single frame.Conversion — the command is a list of arguments passed straight to the process, without the system shell, so a file name can't turn into a command. FFmpeg is told not to overwrite anything (
-n), and the app picks a free name for the result.Progress — the app reads it from FFmpeg's output. A file is done only when FFmpeg exits without an error and reports that it has finished.
Cancelling or an error — the unfinished file is deleted, and on an error the window shows FFmpeg's last messages.
Only files on the local disk can be converted. The video doesn't leave your computer: FFmpeg reads it from the disk and writes the result next to the original or in the other panel's folder.
Settings synchronization and the local network
Since version 1.5.0, settings move between computers with a file or over the local network (manual). Either way, nothing goes through a server on the internet.
What has changed since last time
Every item — a server, a terminal, a category, a favorite path, a single setting, the set of keyboard shortcuts — has a version: the time of the change with a counter and the computer's identifier. The app detects changes by comparing the current settings with fingerprints remembered in the sync-state.toml file (without the values themselves; password fingerprints are computed with a key kept in the keychain). That's why it also catches changes typed by hand into settings.toml, and the format of that file doesn't change. A removal leaves a marker with a version, so it's transferred to other computers. When the same item has been changed twice, the newer change wins.
The .ffsync file
The contents are encrypted with AES-256-GCM, using a key derived from your password with PBKDF2-HMAC-SHA256 (600,000 iterations, a random 16-byte salt). Before that, the password is normalized (NFC), so that the same characters typed on different systems give the same key.
The file header — the format marker, the version, the key function parameters, the salt — is covered by the cipher's authentication, so a change of even a single byte shows up when the file is loaded.
Without the password nothing can be read — not the servers, not the computer's name, not the date it was saved; only the header and the file size are visible. The suggested file name contains the computer's name and the date — you can change it when saving. The password can't be recovered.
A foreign file, or one saved by a newer version of the format, is rejected before the app asks for the password.
Pairing
Each installation has its own key (ECDSA P-256) with a certificate that doesn't contain the computer's name. Pairing remembers the hash (SHA-256) of the other side's key.
The six-digit code is computed from the keys of both computers, the exact bytes of their greetings and random numbers from both sides. The responding computer first commits to its random number (it sends its hash), so an intermediary on the network has a one-in-a-million chance that the codes come out the same — and every attempt requires a click on Continue on the other computer. Each opening of the window allows at most three failed attempts (successful pairings don't count), with a 3-second pause after each failed one.
While the code is shown, the window doesn't display the name given by the other computer — only its address and system — and the buttons become active after a second and a half.
Connections
Every connection is TLS 1.2 or 1.3 with certificates from both sides. When fetching settings and files, both sides check that the other side's key matches the one remembered when pairing; during pairing itself, comparing the code plays that role.
While the pairing window is closed, an unpaired computer is refused before the app reads a single byte of its request. While the window is open, the app reads one request from it and accepts only a pairing request. The app accepts connections only from the subnets of enabled Ethernet and Wi-Fi adapters; it skips tunnels, PPP connections and known VPN and virtual machine adapters. This is a list of known adapters, not a guarantee — the pinned key protects against a foreign computer anyway. At most 8 connections at a time and 2 from a single address.
Ports: UDP 28217 (announcements while the pairing window is open, and queries for a paired computer's address — on every connection to it, alongside an attempt at the last known address) and TCP 28217–28220 (the first free one). IPv4 addresses only.
A query for a paired computer's address carries a tag derived from the key agreed when pairing, so only that computer answers it. The announcement while the pairing window is open (512 bytes) contains the computer's name, the system, the TCP port and the beginning of the key fingerprint. Outside the pairing window, the app announces nothing about itself; the computer's name goes only to a paired computer, over an encrypted connection. The certificate with the public key (without the computer's name) is part of every TLS connection — in TLS 1.2, always used when a Mac is the server, it's sent unencrypted.
The service runs only when there are saved pairings or the pairing window is open. If you don't pair computers, the app has no open port and doesn't read the keychain for this purpose. Only one app process runs the service at a time.
Fetching settings is always on request (Synchronize Now) and goes one way: from that computer to this one. The groups selected on both computers are transferred, and server passwords — only to the computers that have been allowed. The sharing computer reads the passwords without any system windows (on macOS — from its own encrypted copy).
The app keeps the computer's identity and the list of pairings in the
sync-lan.binfile, encrypted (AES-256-GCM) with a key derived from the synchronization key in the keychain. Contents: this computer's certificate and private key, the settings sharing switch, and for each paired computer the fingerprint of its public key, its name, system, pairing date, pair discovery key, permission to share passwords, last address and port, and the dates of the last fetches.
Files of a paired computer
File sharing is a separate permission, off by default. Every request and every chunk of a transfer checks that the permission and the pairing are still in force — turning sharing off (after OK) or removing the pairing on the computer that shares the files stops a transfer in progress.
Files go in chunks of up to 128 KiB, with no size limit. Copying and moving from this computer's disk and between paired computers doesn't load the file into memory; between two paired computers, a file passes through a temporary copy on this computer's disk. Preview with F3, editing with F4 and copying from an FTP/SFTP server to a paired computer load the whole file.
Writing at the destination is atomic: cancelling, a dropped connection, the wrong data length or a revoked permission leave the previous file, and the temporary file is deleted.
The computer with the drives checks the paths and the identity of the files itself, so a file can't be moved onto itself and a folder can't be copied into its own subfolder, not even through another path to the same place. Drive roots can't be deleted, moved or overwritten.
Data and security
What the app stores
| What | Where |
|---|---|
| settings (including changed keyboard shortcuts), saved connections (without passwords), favorite paths, terminals | settings.toml in the settings folder — macOS: ~/Library/Application Support/FlyingFiles/, Windows: %APPDATA%\FlyingFiles\, Linux: ~/.config/FlyingFiles/ |
| settings backups | settings.toml.bak.0 … .bak.5 next to it |
| FTP/SFTP server passwords | macOS Keychain / Windows Credential Manager / the keyring on Linux (GNOME Keyring, KWallet), service FlyingFiles FTP |
| transfer log | logs/transfers.log in the settings folder |
| network share addresses (macOS) | network-mounts.toml in the settings folder |
| extracted archives | the system's private temporary folder, deleted when the archive is closed |
| files over 4 MB from a server or an archive opened for viewing or editing | a copy in the system's temporary folder, deleted when the window is closed |
| settings synchronization state (fingerprints and versions of items, without the values) | sync-state.toml in the settings folder |
| an encrypted copy of the passwords for synchronization (macOS only) | sync-passwords.bin in the settings folder |
| this computer's key and the list of paired computers, encrypted | sync-lan.bin in the settings folder (Windows: %LOCALAPPDATA%\FlyingFiles\) |
| the settings synchronization key | Keychain / Credential Manager, service FlyingFiles Sync |
Passwords
Passwords are stored in the system password store — the macOS Keychain, Windows Credential Manager or the keyring on Linux (GNOME Keyring, KWallet). The system encrypts them, and on macOS it also controls which apps can read them.
Outside the system store, passwords go only into encrypted synchronization files: into the
.ffsyncfile, if you save it with passwords, and on macOS — into thesync-passwords.bincopy, encrypted with a key from the Keychain, thanks to which synchronization doesn't ask the Keychain about each password separately.The settings file never contains passwords.
The app reads a password only when it connects to that server, when the connection is edited or when settings are synchronized with passwords, not at startup.
In the server conversation log, the password is masked (
PASS ********).
The settings file
Saving is atomic (a temporary file, then a swap), with a lock that protects against two windows saving at the same time.
On macOS, the file has owner-only permissions (
0600), because it contains server addresses and logins.When reading, the app tolerates missing and unknown keys, and when saving, it keeps keys it doesn't know — manual additions and settings from older versions aren't lost.
Backups are made before saving.
Terminals
A terminal's address and username may contain only safe characters (letters, digits, ., -, _, : and the brackets of IPv6 addresses). This way, a saved entry can't sneak an extra command into the terminal.
Known security limitations
The FTPS server certificate isn't verified, and the SFTP host key is accepted without checking it against a list of known hosts. Encryption protects against eavesdropping, but not against an impostor server.
Plain FTP encrypts nothing — neither the password nor the files.
Distribution and updates
macOS
The app is signed with a Developer ID certificate, runs with the Hardened Runtime enabled and is notarized by Apple. The notarization ticket is stapled to the app and to the
.dmgdisk image, so the system can check it without a network connection.The app has one additional permission: controlling other apps (Apple Events) — solely to open an SSH or Telnet connection in the Terminal app. macOS asks for consent the first time it's used.
Launched from the disk image, the app copies itself to
~/Applications. Installing in the user's folder means updates don't require an administrator password.Updates (Velopack library) come from
https://nci.pl/flyingfiles/releases/osx-arm64/over HTTPS. The app checks the list of releases at startup (you can turn this off in Settings) and on request; it downloads the package, replaces itself and restarts only after you agree. The app inside the package is signed with the same Developer ID certificate and notarized, just as with the first installation.The app has a description of its local network access: macOS may ask for permission the first time FlyingFiles connects to a device on the local network — for example when pairing computers.
The app isn't in the Mac App Store: the store's sandbox doesn't allow moving freely around the whole disk or controlling Terminal — which is exactly what a file manager is for.
Windows
The app is released as an MSIX package in Microsoft Store. The package is signed by Microsoft, so installation goes through without SmartScreen warnings.
Updates are installed by Microsoft Store. The app recognizes that it's running from a Store package and turns off its own update mechanism. Instead, it asks the Store — since version 1.5.0 also at startup — and Help → Check for Updates… shows the download progress and installs the update; when the Store fails, the app offers to open its Store page.
The package declares firewall rules for the local network ports (UDP 28217, TCP 28217–28220). Windows adds them during installation and removes them when you uninstall, with no firewall window and no administrator rights.
The app runs as a regular Windows app with your account's permissions. It doesn't need any special consent to access files, and it keeps its settings in the regular
%APPDATA%\FlyingFilesfolder.
Privacy by design
No telemetry, analytics, accounts or ads.
The app's only network connections are: your FTP/FTPS/SFTP servers, your network shares, computers on your local network when you pair computers or have paired ones, and
nci.pl— at startup (you can turn this off) and when you choose Check for Updates… (macOS and Linux). The Windows version from the Store asks Microsoft Store, not our server.The video preview uses the system's Quick Look on your computer; nothing is sent anywhere.
Video conversion runs FFmpeg on your computer, and Minify files changes files in the app's memory before they reach the destination. Neither feature uses any online service.
The Markdown view doesn't download images from the internet — it shows only images from the computer's disk, and a link opens only when you click it.
Full text: privacy policy.
Languages
All interface texts are in a single translation file, in Polish, English, Spanish, German and French. Every text exists in all five languages, which automated tests check. On first launch the app picks the language of your system (English when the system uses a language the app doesn't know); after that your choice from the Language menu is kept in the settings file. The language changes immediately, without restarting the app.
Quality
More than 3,700 automated tests check the app's logic and windows — also without a screen — on macOS and on Windows. The tests check pairing and local network connections on the computer's loopback interface.
Every bug fix starts with a test that reproduces the bug.
FTP and SFTP support is additionally checked on real servers with a separate tool that goes through a list of operations: connecting, listing, uploading, downloading, verification, cancellation and reconnecting.
History
Up to version 0.1.0, FlyingFiles was a Python app with a Qt interface. In September 2026, the app was rewritten from scratch in C#, following a detailed specification of how the old version behaved, to gain native startup speed, signing and notarization on macOS, a Microsoft Store package and a single codebase for both systems. The first stable release of the new version is 1.0.0, from September 13, 2026, and the release with new features is 1.1.0, from September 16, 2026. Changelog.
Open source libraries
| Library | License | Used for |
|---|---|---|
| .NET 10 | MIT | runtime |
| Avalonia, Avalonia.Themes.Fluent | MIT | user interface |
| CommunityToolkit.Mvvm | MIT | MVVM pattern |
| Tomlyn | BSD-2-Clause | TOML settings file |
| SharpCompress | MIT | bzip2, xz, 7z, RAR archives |
| Joveler.Compression.XZ, liblzma | MIT; public domain / 0BSD | writing xz archives |
| FluentFTP | MIT | FTP and FTPS |
| SSH.NET, BouncyCastle.Cryptography | MIT | SFTP |
| Microsoft.Extensions.Logging.Abstractions | MIT | SSH.NET dependency |
| Avalonia.AvaloniaEdit | MIT | text editor |
| SkiaSharp | MIT | images |
| Velopack | MIT | updates on macOS |
FFmpeg isn't part of the app or its packages: FlyingFiles runs it as a separate program when it's installed on the system. The disc burning tools — drutil on macOS and xorriso on Linux — are separate programs in the same way.
The current versions are shown in the Help → About window.