SwiftNIO SSH: building blocks for SSH servers and clients in Swift
SwiftNIO SSH is a programmatic implementation of SSH using SwiftNIO
At a glance
- What is it?
- SwiftNIO SSH is a programmatic implementation of SSH for Swift, closer to libssh2 than to OpenSSH, so it gives you the networking and cryptographic layers of an SSH endpoint without shipping a ready-made client or server. It suits a Swift service that wants to accept SSH connections and do something other than a shell with them, and the detail to understand first is that the version support matrix is a table of Swift versions rather than a single floor.
- Who is it for?
- Adopt SwiftNIO SSH if you need to accept or initiate SSH connections from a Swift service, since it handles the protocol, the cryptography and the channel multiplexing without requiring a shell implementation.
- Can I use it commercially?
- Yes. Apache-2.0 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 16 days ago.
- What is it written in?
- Mainly Swift, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What it is, and what it is not
SwiftNIO SSH is a programmatic implementation of SSH, that is, a collection of APIs that allow programmers to implement SSH-speaking endpoints. Critically, this means it is more like libssh2 than OpenSSH.
That comparison is the single most useful thing in the README, because SSH has two very different kinds of implementation and they are easy to confuse. OpenSSH is a program you run, with a client, a server, a configuration file format and a policy model. libssh2 is a library you link, which gives you the ability to speak SSH but leaves the decisions to you. This project is in the second category.
So the statement that SwiftNIO SSH does not ship production-ready SSH clients and servers, but instead provides the building blocks for building this kind of client and server, is precise. If you want an ssh binary you already have one on every machine. If you want a service that speaks SSH and does something unusual with the sessions, you need the protocol layer and you have to build the rest.
The reason to provide a programmatic SSH implementation at all is explained next, and the first reason given is about interactivity. SSH has a unique relationship to user interactivity: technical users are highly accustomed to interacting with SSH interactively, either to run commands on remote machines or to run interactive shells. Having the ability to programmatically respond to these requests enables interesting alternative modes of interaction.
The prior examples named are worth reading because they show the range. Twisted's Manhole uses a programmatic SSH implementation called conch to provide an interactive Python interpreter within a running Python server, so you connect with ssh and land in a Python prompt served by the running application rather than on a shell. ssh-chat is an SSH server that provides a chat room instead of regular SSH shell functionality. And the README notes that innovative uses can also be imagined for TCP forwarding.
The second reason is more mundane and probably more common. It is not uncommon for services to need to interact with other services in a way that involves running commands, and while `Process` solves this for the local case, sometimes the commands that need to be invoked are remote. While `Process` could launch an `ssh` client as a sub-process, it can be substantially more straightforward to simply invoke SSH directly. That is libssh2's target use-case, and SwiftNIO SSH provides the equivalent of the networking and cryptographic layer of libssh2, allowing motivated users to drive SSH sessions directly from within Swift services.
The project is Apache 2.0 licensed, written in Swift, the default branch is main, and the last push was on 2026-10-07. The releases are 0.15.0 from 2026-07-28, 0.14.1 from 2026-07-15 and 0.14.0 from 2026-07-06.
The feature set, and the cipher policy
SwiftNIO SSH supports SSHv2 with a feature set that is short enough to read in full.
All session channel features, including shell and exec channel requests. Direct and reverse TCP port forwarding. Modern cryptographic primitives only: Ed25519 and ECDSA over the major NIST curves, P256, P384 and P521, for asymmetric cryptography, AES-GCM for symmetric cryptography, and x25519 for key exchange. Password and public key user authentication. And support for all platforms supported by SwiftNIO and Swift Crypto.
The cryptographic line is the one to notice, and the phrase doing the work is modern only. This is not a library that will negotiate an old algorithm for compatibility with an old client. Ed25519 and the NIST curves for signatures, AES-GCM for encryption, x25519 for key exchange. Each of those is a current recommendation, and choosing to support only them means the codebase has one code path per operation rather than several, and that no negotiation logic has to handle a legacy algorithm being requested.
That is a deliberate trade. A library that supports the whole historical range of SSH algorithms has to carry them, and every one of them is a liability. A library that supports only the modern ones cannot talk to a client that offers nothing else, and that is the correct outcome for a library aimed at new services rather than at connecting to arbitrary legacy hosts.
The port forwarding support is worth pausing on too, because it is the feature that turns a protocol library into something you can build a tunnel on. Direct forwarding, which is the familiar `-L` behaviour of forwarding a local port to a remote one, and reverse forwarding, which is the `-R` behaviour of having a remote service appear on the local side. Both are the kind of thing that is tedious to implement over a protocol API and easy to implement if the library has already done the plumbing.
The platform support line is also more specific than it sounds. Supporting all platforms supported by SwiftNIO and Swift Crypto means the library inherits the reach of the two projects underneath it, and in particular inherits the availability of the cryptography from Swift Crypto rather than requiring an OpenSSL binding on each platform.
The dependency on Swift Crypto is worth understanding as a design choice rather than an implementation detail. SSH needs a cryptographic primitive set, and the two options in the Swift world are binding to a system library, which means a different binding per platform, or using Swift Crypto, which is a Swift implementation of the same primitives. The second keeps the package free of system dependencies and makes the cipher policy above straightforward to state.
The Swift version matrix
The minimum Swift version supported by SwiftNIO SSH releases is detailed in a table, and it is the kind of detail that decides whether a dependency can be adopted at all.
The most recent versions of SwiftNIO SSH support Swift 5.9 and newer. The table then walks backwards through the release history. Versions from 0.0.0 up to but not including 0.3.0 need Swift 5.1. From 0.3.0 to below 0.4.0 needs 5.2. From 0.4.0 to below 0.5.0 needs 5.4. From 0.5.0 to below 0.6.2 needs 5.5.2. From 0.6.2 to below 0.9.0 needs 5.6. From 0.9.0 to below 0.9.2 needs 5.8. From 0.9.2 to below 0.10.0 needs 5.9. From 0.10.0 through 0.12.0 needs 5.10. From 0.12.0 to below 0.13.0 needs 6.0. And from 0.13.0 onwards, 6.1.
Two things stand out. The floor has moved steadily, one or two releases at a time, and it has now reached a Swift 6 language mode requirement. That is normal for a package that wants to use modern concurrency and strict concurrency checking, and it means adopting the current release of SwiftNIO SSH means adopting Swift 6.1 or newer.
The second thing is the pace of the change. Nine version bumps in the table means the project has raised its floor nine times, and each raise is a deliberate decision to drop support for an older compiler. For a package whose users are server operators who cannot always move their toolchain immediately, that is the constraint that matters.
So the practical advice is to pick the row rather than the release. If your project is on Swift 5.10, releases from 0.10.0 through 0.12.0 work; the most recent releases require Swift 6.1. If you are on Swift 6.0, you need 0.12.0. If you are on Swift 6.1 or later, you can take anything from 0.13.0 up. And if you are stuck on something older, the table tells you which older release of SwiftNIO SSH to pin, which is exactly the information a table like this exists to provide.
One oddity in the table is worth a mention. The 0.5.0 row specifies Swift 5.5.2 rather than 5.5, and the range boundary at 0.6.2 is oddly precise. Those are the kind of details that only appear when the requirement was set to the exact patch release that introduced the needed feature, which is a good sign about the care taken.
How the API is shaped, and the channel model
SwiftNIO SSH provides a SwiftNIO `ChannelHandler`, `NIOSSHHandler`, and this handler implements the bulk of the SSH protocol directly. Users are not expected to generate SSH messages directly. Instead, they interact with the `NIOSSHHandler` through child channels and delegates.
That division of labour is the key to using the library. SSH is a multiplexed protocol: each SSH connection is subdivided into multiple bidirectional communication channels called, appropriately enough, channels. SwiftNIO SSH reflects this construction by using a child channel abstraction. When a peer creates a new SSH channel, SwiftNIO SSH will create a new NIO `Channel` that is used to represent all traffic on that SSH channel.
Within this child `Channel` all events are strictly ordered with respect to one another, but events in different channels may be interleaved freely by the implementation.
That ordering guarantee is worth understanding carefully, because it is what makes the library usable with SwiftNIO's concurrency model. Within one SSH channel you get ordered delivery, which is what a protocol implementation needs to make progress correctly. Across channels you get no ordering guarantee, and you should not rely on one. So if two SSH sessions are running over one connection and one of them is where your data arrives, the ordering between them is not defined, but the ordering within each is.
The handler sits in the NIO channel pipeline and spawns child channels downwards, and each child channel is where the user's own handler lives. The diagram in the README shows this: a NIO Channel containing the NIOSSHHandler, with the handler fanning out to SSH child channels, each of which contains a user handler box.
So a user of the library writes a handler per SSH channel, exactly as they would write a handler per TCP connection with NIO. That symmetry is what makes the library idiomatic for a Swift developer: the mental model is not SSH concepts but NIO concepts, and the protocol is handled underneath.
The consequence is that a user never sees an SSH message type. They see NIO events: channel active, channel inactive, data readable, data writable. The SSH-level concepts, the channel open requests, the authentication exchange, the key exchange, are all handled by the handler and surfaced as the creation of a child channel with the right state.
The repository, and what it implies about the project
The top level of the repository is the standard layout for a Swift package, and it is worth reading for what it does and does not contain.
There is `Package.swift` as the package manifest, `Sources/` for the library, `Tests/` for the test suite and `Benchmarks/` for performance measurement. There is a `dev/` directory, which in a SwiftNIO project is usually the place for developer scripts and tooling. And there are the standard configuration files, an `.editorconfig`, a `.swift-format` file for the formatter, a `.spi.yml` for the Swift Package Index, a `.licenseignore` for the dependency license check, and a `CONTRIBUTING.md`.
The presence of a `Benchmarks/` directory is the item worth noting. A protocol implementation has obvious performance characteristics that matter, because the cost per byte and per key exchange is what determines whether a service can handle a given number of concurrent sessions. A library that ships benchmarks alongside its tests is making a statement that it intends to be measured.
The `.swift-format` file is also worth a moment. Swift's official formatter arrived with the Swift 6 toolchain, and a package that configures it and checks it in a repository root is a project that has adopted the current tooling rather than carrying its own formatting rules.
The `.spi.yml` file registers the package with the Swift Package Index, which is the community registry and documentation site for Swift packages. Its presence means the package is discoverable there, which for a library rather than an application is how people find it.
And the `.licenseignore` file is the piece that tells you about the dependency set. SwiftNIO projects carry a licence check in CI, and an ignore file is the list of dependencies whose licences need a human judgement rather than an automated match. Its presence means the dependency tree is checked, which for a cryptographic library is not a formality.
So the repository is a well-equipped library repository: tests, benchmarks, formatting, a licence check, CI configuration in the `.github/` directory and documentation of the contribution process. That is the profile of a project maintained by a team rather than by one person, which matches the Apple attribution on the repository and the SwiftNIO family's general shape.
Editorial conclusion
Adopt SwiftNIO SSH if you need to accept or initiate SSH connections from a Swift service, since it handles the protocol, the cryptography and the channel multiplexing without requiring a shell implementation. Do not expect it to give you a drop-in ssh client, because the project is explicit that it ships building blocks rather than production-ready endpoints, and check first which Swift version your project targets, because the supported floor has moved with each release and the matrix is documented per version range.
Frequently asked questions
What is SwiftNIO SSH?
It is a programmatic implementation of SSH for Swift, meaning a collection of APIs that let programmers implement SSH-speaking endpoints. The README is explicit that it is more like libssh2 than OpenSSH: it provides the networking and cryptographic layers of SSH but does not ship production-ready clients or servers. The licence is Apache-2.0.
Which cryptographic algorithms does SwiftNIO SSH support?
Modern primitives only: Ed25519 and ECDSA over the NIST curves P256, P384 and P521 for asymmetric cryptography, AES-GCM for symmetric cryptography, and x25519 for key exchange. It also supports password and public key user authentication, direct and reverse TCP port forwarding, and all session channel features including shell and exec channel requests.
How do I use SwiftNIO SSH in a Swift service?
Through the NIOSSHHandler, a SwiftNIO ChannelHandler that implements the bulk of the SSH protocol. Users are not expected to generate SSH messages directly. Instead they interact with the handler through child channels and delegates, with a new NIO Channel created for each SSH channel the peer opens, and events strictly ordered within a channel while interleaving freely across channels.
What Swift version does SwiftNIO SSH require?
The most recent versions support Swift 5.9 and newer, and the project publishes a table of the minimum Swift version per release range. Versions from 0.13.0 onwards need Swift 6.1, 0.12.0 to below 0.13.0 needs 6.0, 0.10.0 through 0.12.0 needs 5.10, and older releases need correspondingly older compilers back to Swift 5.1 for versions below 0.3.0.
What kinds of thing can be built with a programmatic SSH implementation?
SSH has a unique relationship to user interactivity, so a service can respond to interactive requests in ways other than a shell. The README points to Twisted's Manhole, which uses a programmatic SSH implementation called conch to give an interactive Python interpreter inside a running Python server, and to ssh-chat, an SSH server offering a chat room instead of shell functionality. It also notes that TCP forwarding is another use.
Is SwiftNIO SSH still being developed?
The repository is not archived and the last push was on 2026-10-07. Releases 0.15.0, 0.14.1 and 0.14.0 came in July 2026, the repository carries a Benchmarks directory alongside the Tests directory, and the tooling includes a .swift-format configuration, a .spi.yml registration for the Swift Package Index and a .licenseignore for the dependency licence check.
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/apple-swift-nio-ssh)Was this useful?