Launching today

Upstream FTP
A fast, beautiful, and native FTP/SFTP client for macOS
104 followers
A fast, beautiful, and native FTP/SFTP client for macOS
104 followers
Upstream is a native, modern, and lightweight FTP/SFTP client built exclusively for macOS. Designed for speed and seamless integration, it ditches heavy, outdated interfaces to give developers and sysadmins a fast, secure, and beautiful file transfer experience.









Upstream FTP
That tradeoff makes sense given the sandbox — manual key authorization is the honest cost of being App Store-distributed. ProxyJump is the one I'd watch most: for anyone living behind a bastion, rebuilding jump hosts by hand is the gap between a two-minute migration and an afternoon, so that backlog item is the real power-user unlock. Honoring Match/Include blocks in the parser would cover a lot of those setups too.
Upstream FTP
@hi_i_am_mimo Thanks, Valeria; your contribution is invaluable to me. You will certainly see what you highlighted included in the next release!
Foyer
The native Mac client space for FTP is genuinely underserved. Most people end up on Cyberduck or Transmit and just stay there out of habit rather than because those tools are great. What I'm curious about is where "fast" is coming from specifically. Is this a smarter connection-handling layer, local caching of directory listings, or something at the rendering level? And does it handle edge cases like servers with slow PASV negotiation or broken directory listing formats, because that's where the legacy clients tend to silently fail and leave you guessing.
Upstream FTP
@fberrez1 Hi! Thanks for the great questions. You've hit on exactly the pain points we set out to solve with Upstream. Here is how we handle "fast" and those tricky FTP
edge cases under the hood:
1. Where does "fast" come from?
• SwiftNIO Transport: Instead of wrapping legacy C libraries (like libcurl) or using blocking sockets, Upstream is built on top of Apple's SwiftNIO (the same
high-performance, event-driven, non-blocking network framework used for Swift on Server).
• Browsing & Transfer Isolation: We decouple directory browsing from file transfers. Transfers run on a dedicated concurrent connection pool (managed via Swift
Concurrency Actors), ensuring the directory viewer remains completely responsive and lag-free even during multi-gigabyte uploads/downloads.
• Background Parsing & SwiftUI Rendering: Directory sorting, filtering, and parsing happen entirely on background actors before updating the SwiftUI Table with
stable identifiers, avoiding main-thread freezes.
2. Smart PASV Negotiation (NAT & IPv6)
• Many servers behind NAT misconfigure their passive settings and return unroutable private or loopback IPs (like 192.168.x.x or 127.0.0.1) during the PASV
handshake. Upstream explicitly checks for this and automatically overrides it, falling back to reuse the control connection's host (which is guaranteed to be
routable).
• On IPv6 connections, it automatically switches to EPSV (Extended Passive, RFC 2428) to negotiate only the port, preventing passive negotiation hangs.
3. Directory Listing Formats
• Upstream queries the server's features (FEAT) and prioritizes MLSD (RFC 3659) for a standard machine-readable format.
• If MLSD isn't supported, we fall back to a custom, regex-free UNIX LIST (ls -l) parser that tolerates irregular column spacing, localized date formats, and
symlink patterns.
4. No Silent Failures
• We use a strict 15-second connect timeout on both control and data channels to fail fast instead of hanging forever.
• Every command and response is piped into a live Console/Message Log (similar to FileZilla) at the bottom of the screen. If a legacy server fails to negotiate,
you won't be left guessing—you can inspect the raw protocol logs and exact FTP error codes in real time.
Give it a try and let us know how it handles your toughest server connections!
building on SwiftNIO instead of wrapping libcurl is the right long-term call - you get real async I/O without fighting legacy C semantics. the dual-pane layout is the correct UX choice too; every sysadmin who's used Midnight Commander or WinSCP has that muscle memory. two things I'd check before switching from Transmit: macOS keychain integration for SSH key passphrases (the workflow killer is re-entering keys on every session), and whether it handles S3/Backblaze remotes or stays pure FTP/SFTP. the FTP-only constraint is fine, but people will ask.
Upstream FTP
@galdayan Thanks for the encouraging words! We firmly believe that native SwiftNIO and a classic dual-pane interface are key to making a professional client feel right on macOS.
Since this is our first release, some features might not be 100% perfect yet, but with your feedback and help, we'll be happy to refine everything and make it perfect.
You can easily run Upstream alongside Transmit for a while—since Upstream is free to download and offers a fully functional free tier, you can test it on your daily workflows with zero risk!
Here is how we handle your two check-points:
1. macOS Keychain for SSH Keys:
Yes, absolutely. We store both the SSH private key content itself and its optional passphrase securely in the native macOS Keychain (via usesKeyAuth, keyRef, and passphraseRef).
Once imported via a standard file dialog, the app resolves them automatically on every connection. You do not need to re-enter your passphrases or select keys again between sessions.
2. S3 and Cloud Providers:
Right now, Upstream stays strictly pure FTP, FTPS, and SFTP.
We chose to focus entirely on perfecting these standard protocols first, ensuring high performance,
connection pooling, and NAT handling. That said, S3, Backblaze B2, and WebDAV support are definitely on our roadmap for future updates as we expand beyond this initial version.
Native-and-lightweight is exactly why I would switch off the Electron FTP clients — the wrapper bloat is real. On the security side, where do credentials live: does it use the macOS Keychain and read SSH keys/agent from ~/.ssh, or keep its own store? And can I import existing connection profiles from something like Transmit or FileZilla, or is it all manual entry on day one?
Upstream FTP
@hi_i_am_mimo Thanks! Avoid the Electron wrapper bloat is exactly why we went 100% native (Swift, SwiftUI, and SwiftNIO). To answer your questions on security and profile migrations:
1. Where do credentials live?
• macOS Keychain: All passwords and private key passphrases are stored securely in the native macOS Keychain (never in plain text database files).
• iCloud Keychain Sync: The app supports iCloud synchronization, meaning your credentials can be securely synced across all your Macs.
2. How are SSH keys handled with the App Sandbox?
• Sandbox Compliance: Because Upstream is distributed on the Mac App Store, it is sandboxed and cannot silently read your ~/.ssh directory or run a background SSH agent.
• Key Import: You can securely import your OpenSSH private keys (fully supporting ed25519 and RSA) using the macOS native open panel. Once selected, keys are parsed and the configuration is saved securely.
3. Can you import existing profiles?
• Yes, day-one import is supported! You can import your existing connection profiles directly from:
• FileZilla (via sitemanager.xml or XML export files)
• SSH Config: You can import your existing hosts and configurations directly from your ~/.ssh/config file to spin up SFTP profiles instantly.
• Transmit imports are currently on our roadmap.
Native + Keychain + sandboxed key import via the open panel is exactly the posture I want, and good to know it never silently reads ~/.ssh. On the ssh config import: does it honor per-host directives like ProxyJump/bastion hops and IdentityFile, or does it just pull Host/HostName/User and leave jump-host setups to rebuild by hand?
Upstream FTP
@hi_i_am_mimo You are spot on. Currently, the SSH config importer is basic: it only extracts Host, HostName, User, and Port to quickly populate your connection bookmarks.
It does not honor complex directives like ProxyJump/bastion setups or IdentityFile at import time:
• For IdentityFile, the App Sandbox requires the user to explicitly select and authorize private key files using the native open panel anyway, so keys must be linked manually after import.
• For ProxyJump, it is currently bypassed and those setups will need to be configured by hand.
Since we are in the early stages, improving the SSH config parser to handle more advanced options and adding support for jump hosts is definitely going on our backlog for future power-user updates!
Thanks Valeria !