croc: the curl install is the only one that can replace its own binary
GitHub describes it as Easily and securely send things from one computer to another :crocodile: :package:. The repository metadata lists Go as its primary language. The metadata lists the MIT license. This article stays within the project description and details documented in the GitHub repository README.
At a glance
- What is it?
- A Go CLI for transferring files between two computers peer to peer with a relay fallback and end-to-end encryption using PAKE, installable through a dozen package managers plus a browser. The install method decides whether the tool can update itself, the Debian fallback never registers a repository, and the Docker image runs a relay rather than a client.
- Who is it for?
- Use croc when you want a single binary that transfers between two machines with no server to run, and when you are willing to accept a background release check during transfers. Choose the install route deliberately rather than by convenience, because the curl installer is the only one that can replace its own binary and the Debian downloaded-package route never will.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The update story changes completely depending on how you installed
The install section is short, but the paragraph after it is where the design shows.
curl https://getcroc.com | bashInstallations made by that command can use `croc update`, with `croc upgrade` as an alias, to verify and install a stable release when the executable is user-writable, and `--yes` skips the confirmation. Package-managed and other installations are never overwritten, and the command prints the appropriate upgrade guidance instead. So the same binary behaves differently depending on where it came from. There is a second layer on top. When the CLI sends or receives a transfer it checks for a newer release at most once every 24 hours, in the background, and the notice appears only after the transfer finishes. Network and release-service failures in those background checks are ignored, and `--quiet` suppresses the notice entirely, while `croc update --check` forces a check on demand. In practice that means a file transfer can make an outbound network call you did not ask for, and a pinned package deliberately stays pinned.
The Debian fallback never registers a repository, so upgrades are manual forever
Debian and Ubuntu have two routes and the second one has a stated downside. The first is a third-party archive, pkg.haus, which provides Debian packages, installed with a single command.
sudo apt install crocThe second route exists for a release that includes upstream `.deb` downloads, and for older releases whose configured repositories do not carry croc at all. You find the file matching your architecture with `dpkg --print-architecture`, then install the downloaded file.
sudo apt install ./croc_VERSION-1_ARCH.debThe page is explicit about what this costs. It does not add an APT repository, and to upgrade it you download a newer package. So the moment you take this route you have opted out of `apt upgrade` for this tool permanently, and every future version is a manual download followed by a manual install. The same pattern is set out for Fedora and openSUSE with `dnf` and `zypper`, where the page adds that those packages install the CLI, manual, license notices, and shell completions, require `ca-certificates`, start no background services, and are left intact by `croc update`.
Alpine stable branches can hand you a release several versions behind
The Alpine section is the only one that warns you about version drift before you install. It tells you to enable the community repository for your Alpine release, then run a single command.
apk add crocThe instruction that matters comes next: check the package index for your branch's version, because stable branches can carry older releases, and consult the distribution status document before selecting one. That is a warning from the project about its own packaging, not a general caveat. The consequence is that on Alpine your `apk` database will happily install whatever the branch pins without telling you that you are several patch releases behind, and since a package-managed install is never overwritten by the tool's own updater, you have no automatic path forward either. If your work depends on a recent croc behaviour, check the version the branch actually carries before you commit to Alpine, and pick the Nix route if you want the version you asked for.
environment.systemPackages = [
pkgs.croc
];That NixOS snippet pins `pkgs.croc` from your channel rather than from a distribution's archive, which is the difference between the two approaches in one line.
The Docker one-liner can only reach the directory you launched it from
Rather than publishing a client image workflow, the Docker section hands you a shell function to paste into your profile.
croc() { [ $# -eq 0 ] && set -- ""; mkdir -p "$HOME/.config/croc"; docker run --rm -it --user "$(id -u):$(id -g)" -v "$(pwd):/c" -v "$HOME/.config/croc:/.config/croc" -w /c -e CROC_SECRET docker.io/schollz/croc "$@"; }Three consequences follow from reading the mounts. The working directory is bind-mounted to `/c` and set as the workdir, and the page says croc via Docker will only work within the current directory and its subdirectories, so any path outside it is simply unreachable. The config directory is bind-mounted separately from `$HOME/.config/croc`, which is what lets a transfer phrase survive between runs. And the pairing secret is passed through the environment as `CROC_SECRET`, so it is in your process environment for the life of the run. Finally, the function shadows the real binary in your shell, which means that with this in your profile you have no croc at all whenever Docker is unavailable.
The container's default command starts a relay, not a client
The image in this repository is not a packaging of the sender. The entrypoint is a script called `croc-entrypoint.sh` and the default command is `relay`. The image exposes port 8080 and then a run of ports from 9009 to 9017, and the health check probes whichever relay ports are configured, resolving them in order from `CROC_RELAY_PORTS`, then `CROC_PORTS`, then `CROC_PORT`, defaulting to 9009. It runs as `nobody`, and it creates a storage directory owned by that user. So the honest reading is that this is a self-hosted relay image for people who want the fallback path under their own control, which is a genuinely useful thing to have and not what most people assume they are getting when they run the image. It also sits in deliberate tension with one of the tool's headline claims, that no local server or port forwarding is needed. Clients need neither, but a relay does need to be reachable, and reachability is exactly what those exposed ports are for.
CGO is off and the whole dependency graph ships inside the binary
The build configuration is consistent across the Makefile and the Dockerfile, and it is the standard recipe for a portable static binary. The build flags are `-buildvcs=false -trimpath -tags netgo,osusergo`, the linker flags are `-s -w -buildid=`, and `CGO_ENABLED=0` is set for both the main binary and the web binary. The module path carries the major version, `github.com/schollz/croc/v11`, and the manifest requires Go 1.27.0, so building from source needs a recent toolchain and installs with `go install github.com/schollz/croc/v11@latest`. What is worth pausing on is the dependency list. Alongside the expected pieces, the cryptographic PAKE library, a peer discovery library, CBOR encoding, QR code generation, and a hash library, the graph includes `tailscale.com`, `tailscale/gliderssh`, and `gvisor.dev/gvisor`, which is a userspace network stack. None of that is wrong for a tool that supports proxies and LAN discovery, but it means the attack surface of a tool whose entire pitch is security is a large vendored graph rather than a small one.
The test suite is split into two race files, and two CI systems are still in the tree
Two test files sit at the root of the repository, `race_disabled_test.go` and `race_enabled_test.go`, which is the Go convention for compiling the same suite twice, once with the race detector active and once without. That is a reasonable arrangement for a tool that does concurrent network work, and it does mean the concurrency-sensitive paths get exercised under both configurations. What it also means is that which file applies depends on how you invoke the test command, so a green local run tells you less than it appears to about which configuration you actually tested. The same pattern shows up in the CI configuration. The README badge points at a GitHub Actions workflow, and `.github/` is present, but a `.travis.yml` is still in the tree. Two CI systems for one repository is not an error, but it does split the question of what runs on a pull request across two files in two different formats, and the older one is not obviously marked as legacy.
Every GUI is a third-party project, and the browser is the only official alternative
The official surface is the CLI plus a browser at getcroc.com, and the page is clear that the browser version is fully compatible with the CLI, so you can send from one and receive with the other without installing anything. Everything graphical beyond that is somebody else's work. On Android there are three F-Droid apps, described as an original Go port with a basic UI, a native Kotlin and Jetpack Compose client with a mobile-first interface, and a cross-platform Flutter GUI for Android, Windows, and Linux that wraps the croc binary as its transfer core. On the desktop there are community-built apps, one of which bundles the binary and adds drag-and-drop transfers, QR codes, LAN mode, and relay and proxy options. The wrapping detail is the one to note. A Flutter or desktop client that wraps the croc binary still needs that binary present, so it is an interface over the CLI rather than an independent implementation, and its compatibility ceiling is the version of the binary it ships or finds.
Editorial conclusion
Use croc when you want a single binary that transfers between two machines with no server to run, and when you are willing to accept a background release check during transfers. Choose the install route deliberately rather than by convenience, because the curl installer is the only one that can replace its own binary and the Debian downloaded-package route never will. Before you commit, confirm your platform's package actually carries a current version rather than a stale one, and if you run the container, remember the default command starts a relay listening on the network rather than a client you send from.
Frequently asked questions
How does croc file transfer work?
croc transfers files and folders between two computers peer to peer, with a relay fallback when a direct path is not available. The connection is end-to-end encrypted using PAKE, transfers can be resumed if interrupted, multiple files are supported, the networking is IPv6-first with IPv4 fallback, and it can use a proxy such as Tor.
Which file sharing app is the safest, according to croc?
The project does not compare itself with other file sharing tools. What it claims for croc is end-to-end encryption using PAKE, no need for a local server or port forwarding, and the ability to use a proxy, with an author remark that it believes croc is the only CLI file transfer tool doing all of that at once.
What is the best free file transfer software, per croc?
croc does not rank software, including itself. It is MIT licensed and can be installed with a single command that pipes a script from getcroc.com, or through Homebrew, MacPorts, Scoop, Chocolatey, Nix, Alpine, Debian, Fedora, Arch, Termux, FreeBSD, conda, Docker, a Go build, or F-Droid clients on Android.
Is file sharing safe with croc?
croc's stated protections are end-to-end encryption using PAKE, peer to peer transfer with relay fallback, and proxy support. It also states that no local server or port forwarding is required for a transfer, though the self-hosted relay container in the repository exposes ports for the fallback path to be reachable.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/schollz-croc)