[Prospective Vision] Networking

Hello Swift Community.

The Ecosystem Steering Group would like to gather feedback on a prospective vision for Networking in Swift. Vision documents help describe an overall direction for Swift. The actual Swift and Swift ecosystem changes for executing on the vision will come as a series of separate proposals, so concrete details (e.g., specific syntax, API names, etc.) are less important than the overall direction. There is more information about the role of vision documents in the evolution process here.

The text of the introduction of the vision follows. The vision is quite long, so if you find it interesting, please follow the link above to read more.


A Prospective Vision for Networking in Swift

Almost every Swift application touches a network, yet Swift developers face a fragmented landscape of overlapping solutions with no clear guidance on which to choose.

Today, Swift offers multiple networking APIs with overlapping capabilities. Developers who aren't networking experts must determine which tools fit their problem, often with minimal guidance. A suboptimal choice leads to platform-support gaps, missing features, and costly rewrites.

Meanwhile, Swift itself has evolved significantly. The introduction of Swift Concurrency, featuring async/await, structured concurrency, actors, Sendable, and non-copyable types, has transformed how we write asynchronous and performant code. These modern language features open new possibilities for networking APIs: natural expression of asynchronous I/O, safer concurrent access to network resources, and clearer lifecycle management for connections and streams. However, most existing networking APIs predate these capabilities, built around completion handlers, delegates, or reactive patterns that don't leverage Swift's modern strengths.

This document proposes a vision for networking in Swift that addresses fragmentation and embraces modern Swift. We outline goals, describe design considerations that guide the solution space, and present an approach.


This is a prospective vision which has not yet been reviewed by the Ecosystem Steering Group. Even if it is approved by the Ecosystem Steering Group in exactly this form, it is merely laying out a high-level vision for the design and does not constitute pre-approval of any specific ideas in this document. Everything in this document will need to be separately proposed and reviewed.

55 Likes

Thanks for publishing, super happy to see this!

Would be great to address and ideally add to FAQ whether APIs included in this vision could ever become available in Embedded Swift? That would be a good way to expand on "memory-constrained embedded runtimes" point mentioned in the "Goals" section.

6 Likes

This is great news!

One thing I’d like to delve deeper into is how the balance between Swift Open Source and Apple development is going to work. As the Swift project we don’t have control over Apple OSes so how is that going to be managed in terms of competing priorities and releases.

The vision goal mentions aligning NIO and Network.framework - this really needs to be clearly defined. One thing that absolutely cannot happen is having the release cadence tied to Apple OS releases. We can’t have a security vulnerability discovered in the networking stack (and there will be plenty) and then waiting months for an OS release to fix it. We need to be clear about how releases are going to be managed.

Overall, big plus one on this. The server well has been reasonably aligned as an ecosystem and it will be great to see more collaboration in this space. Aligning the client story is sorely needed as there as confusing and competing types and clients to use, with no clear story. Making this clearer and having a clear vision will put the ecosystem in a much better place.

20 Likes

I think that the direction itself makes sense, but IMO this is not ready to be part of the Swift project. As it stands today, the networking stack is not sufficiently flexible to allow for the various needs of different platform. If this is developed further, it would need to be outside the acceptable set of packages that tooling (e.g. DocC) should be allowed to adopt until we can fomulate a sufficiently flexible system to accommodate non-BSD socketing environments. NIO has long avoided supporting Windows and patches tended to stagnate. A more concrete issue would be when looking at if it were possible to support IOCP as a NIO provider found limitations due to threading. My concern is that designing without those portable fundamentals might paint us into a corner (e.g. like with the NIO event loops).

6 Likes

One aspect of networking which I'd like to see considered carefully is unreliable, changing conditions adhoc networking, where timeouts and inconsistent latency are planned for, such as when your network is via radio, and the nodes are moving. This is a concern in robotics, among other applications. Mdns and Multicast use is another part, some folks like that to make video feeds easier to discover in the aforementioned applications.

1 Like

Yes, I’ll take an action to go away and add this callout explicitly. To be clear, not every API will be available in Embedded Swift: some convenience APIs, or extremely flexible APIs, may be inappropriate for that use-case. But it is absolutely a goal to enable a more harmonious networking story in Embedded use-cases.

Absolutely agreed. Your specific concern (tying releases to OS changes) has been front of mind during the drafting of this vision, but I think the broader topic is one of the major areas of discussion that will be coming in the following months.

A critical area we want to knuckle in on as part of executing on this vision is to get to a place where we can say that there is the networking stack. Right now you could argue that there are at least two, and their platform support does not cover all the platforms that Swift supports today, or even fully overlap with each other. I agree with you that this limitation does fundamentally prevent either of these stacks being a proper citizen of the Swift project, and it’s a critical piece that needs to be addressed. To that end:

We should avoid over-indexing on NIO. NIO is a part of the long-term solution, but it is not the only part and it cannot be. That’s not for the technical reason elucidated here though (there is no threading limitation that would prevent IOCP from backing NIO). The important reason is the first part: the NIO project does not care equally about all platforms and all use-cases.

Arguably, both NIO and the Swift community have suffered quite badly from NIO’s role as the de-facto networking solution for Swift outside of Apple’s platforms. That’s not really what NIO was intended to be, and it’s not what its main customers use it for. This effort will be focused on producing an appropriately layered set of abstractions that will enable all sorts of cross platform usage, both with and without NIO.

Relatedly:

It’s important to remember here that NIO is 8 years old. It was designed for a language that is scarcely recognizable now. No typed throws, no non-copyables, no native concurrency, no native synchronization primitives, limited cross-platform buffer types, limited high performance data structure availability, no Sendable, no variadic generics, no built-in clocks, no opaque return types, no primary associated types on protocols, no effectful properties, no multiple trailing closures, no Windows support, no WASM, no Embedded.

The result is that NIO had to bring its own solution to many of these problems. These solutions were never intended to be the Swift solution to the problem: after all, the NIO team were not in any place to do that work. They were enough for NIO to express the constructs it needed to express.

In those 8 years, Swift has defined its own solutions to many of the problems that NIO initially implemented. Futures, Event Loops, and increasingly even ByteBuffer are beginning to look more-and-more like odd ducks. But NIO can’t abandon them easily, because to do so would abandon the vast pile of working code built on top of NIO.

So this vision wants to look less towards a world that makes NIO more available, and more towards a world that approaches the same problem space again. With the language we have now, what networking story would the Swift community build? Where we can take things from NIO, we should; but this vision should not be beholden to the choices NIO made almost a decade ago. Instead, as you rightly suggest, we should be focusing on leveraging the tools Swift has to build things that are portable, and appropriately abstracted.

Absolutely. As part of this effort we’ll be actively including folks who have worked on the networking on Apple’s mobile devices. These devices have exactly this kind of problem, and their expertise will be invaluable, as well as that of the wider community.

16 Likes

Not much to add here, extremely excited about this and confident we'll be able to hash out the a version of this that will benefit the Swift project in its entirety, and not just in some parts of it.

I know for certain the don't-lock-step-with-OS is front and center on people's minds here and I'm hopeful we'll find some workable model here.

Looking forward to all the work and discussions in this area!

4 Likes

Great to see this happening. :smiley:

Our focus is on abstractions and the developer experience atop HTTP. We aim to enable developers to build innovative services with HTTP and Swift

common protocol implementations, such as TLS, HTTP/1.1, HTTP/2, HTTP/3, QUIC, and WebSockets, can be shared rather than reimplemented by each framework. A single, well-tested HTTP/3 implementation benefits every client and server that uses it.

Could you talk about which of the specific tech standards that you list will the emphasis be on, eg I see HTTP/3 and QUIC was never supported by NIO? Earlier HTTP versions are pretty outdated at this point and most apps will likely want to use the latest.

Importantly, disabling a protocol or feature should, if possible, remove any required code from the binary.

Will new Swift tooling be needed for this, or just using what is already there better? The Android workgroup has been discussing this lately also, for better code thinning of Android shared libraries that already dropped FoundationInternationalization and ICU and would like to slim down further.

not reinvent the underlying transport mechanisms.

While I understand the emphasis on existing standard protocols, I think there should also be an attempt to enable protocol innovation by app devs, if not attempting some yourself. I doubt HTTP/3, a shift from the old request-response text protocol to a more streamlined session-oriented protocol is really the best transport for most apps.

Further, it would be good to see new possibilities unlocked, eg using DHTs more so that apps can easily share data locally, say in a group chat or a neighborhood app, without having to hit centralized servers all the time.

I remember with the rise of mobile a decade and a half ago, there was a lot of enthusiasm that it would lead to a golden age of app network protocols, as devs experimented much more with optimizing their app networking.

That hope has decidedly failed, but you could certainly help resurrect it or work on some new approaches yourself, in addition to providing these standards.

4 Likes

I agree. While we absolutely need a good networking library or framework, such a framework would be too large to be a part of the language itself. Indy immediately comes to mind.

I do not expect HTTP/1.1 to ever go away. However, HTTP/3 is a critical feature requirement for this effort.

To be determined. If we can make things work better using what we have, we should. If new tooling is required, we’ll advocate for that.

Agreed. NIO already has substantial support for external developers to implement entirely new transports, and we’ll want to continue this tradition.

3 Likes

Taking my ESG hat off for a second and just expressing my personal opinion.

I think this vision document clearly outlines the need for why this is an important area for the project to tackle. Almost any modern application is networked in some way. At the same time, writing networking stacks is inherently complex and lies full of potential future security problems if not implemented correctly. In my opinion, this is a major motivation why this should be part of swiftlang so that we can provide a powerful, cross-platform, extensible, modern, safe, performant (and more) but most importantly official networking stack. It should drastically improve the day one experience of any developer that comes into the ecosystem and wants to execute a simple HTTP request. While empowering advanced users such as the ones that need to write custom protocol stacks in constrained environments.

I also think that the language matured a lot over the past decade and to me personally it feels like a perfect time to take a step back and rethink "Networking in Swift" with today's Swift features. I am incredibly excited to see how we can integrate networking and in general async I/O into Swift Concurrency.

There are some great replies in this thread already describing some of the challenges to ensure that this networking vision can cater to all these advanced use-cases. I personally believe we can only be successful in solving these challenges by building a deconstructed and distributed solution to networking. What do I mean by this? There are many individual pieces that make up a networking stack such as:

  1. Scheduling and eventing including asynchronous I/O
  2. Currency types such as IPAddress
  3. Network protocol implementations such as TLS, Quic, and HTTP/2
  4. Asynchronous streaming interfaces
  5. Observability
  6. Higher level clients for HTTP, gRPC and more

Our current networking stacks (and solutions in other language ecosystems) are often mixing multiple of these pieces in a single solution. As a concrete example, NIO provides solutions for almost all of the above out of the box by simply importing NIO. As a result, this means if you want to just use the HTTP/1 state machine to plug it into your custom networking code, you have to bring almost the entire NIO stack with it. I think we need to decompose the setup where each individual piece lands in the "right" place and can be used independently of each other. This will unlock us to compose these individual pieces in ways to cater to exactly the use-case instead of building a single monolithic stack that can do everything but becomes incredibly complex to use and to maintain.

3 Likes

Are SMTP, POP3, IMAP, SSH/SFTP planned? I ask because my real-life apps use these.

1 Like

I think any concrete list of network protocols and higher level clients are outside the scope of a vision document. A networking stack should make it easy to implement custom protocols and build clients and servers on top of it. I personally don't think that swiftlang needs to provide implementations for all network protocols and clients that are out there. There are just too many to make this feasible. However, there are a few ones that are very important such as the protocols that compose an HTTP client and server. I think that those are worth solving once and providing an "blessed" solution for.

2 Likes

For some additional context to this vision, there are two new posts to discuss the design of future HTTP clients and servers:

Importantly, those are just discussion threads and have not been reviewed by the Ecosystem Steering Group.

3 Likes

Pretty much nothing is part of the language itself, not even Int nor String nor Array, nor Foundation, nor CoreImage, etc. (But I got the gist of what you are saying (thou shalt keep the language and its standard library small), and I concur with that.) It's good still to have something common, always felt odd to me to use Network framework on mac and something else on unix.

2 Likes

Thank you providing insight into the road forward!

A couple of aspects that are not really mentioned in the vision, but are concerns for me:

  1. testability/test helpers: NIO and Vapor in particular ship with powerful features to aid in writing tests. I hope this topic will be first class citizen in the new vision;
  2. relation to crypto. As networking is so dependent on cryptography, do you expect to keep relying on Swift Crypto and/or provide its own crypto primitives?
  1. Build times. Currently the cross-platform network solution in many cases is SwiftNIO. Although I love SwiftNIO, building SwiftNIO based apps can take a long time, especially in CI where typically build caches are not available. Crypto seems to increase build times even more. Do you consider the delivery mechanism (i.e. binary, toolchain, build from source) as part of the vision?
2 Likes

Testing network code is extremely important to us, and so yes, I expect this will remain important. I’d like to see us make this even more powerful by tackling some of these other areas.

This is still an open. I’d like us to be moving towards a world where we use swift-crypto more and more in the critical path, and separate crypto libraries like swift-nio-ssl less and less. This will also help with build time issues for the folks who end up using both.

But it’s just as important that this stack can meet users where they are, so we’ll need to continue to make sure that there is space for other choices. For example, users may want to use their platform built-in TLS library when it’s available, or leverage smart cards, or any number of other weird and wonderful things. We’ll need to make sure that modularity is kept in mind.

I can’t speak for everyone, but in my mind the delivery mechanism focus should be on how we want users to consume the resulting projects, more than how they affect the build system. I feel the pain of long build times too, and I still think we have a lot of work we can do to make the Swift Package ecosystem behave better with regard to these long builds.

With that said, the delivery mechanism question is very much on the table.

3 Likes

I'm sorry if I was unclear, I didn't mean to say it shouldn't be part of the swiftlang organisation, just that it should not be allowed to be consumed by the Swift distribution. That is, we shouldn't allow packages like DocC and SPM to use them as dependencies until it has been fleshed out sufficiently that it works properly across multiple platform environments, including those that are vastly different from Unix.

Certainly for SwiftPM, having a network stack that supports and works well for all our host platforms will be critical before we adopt it.

I am really looking forward to this effort. It’s a great way to bring all of the Swift community together to work towards a common vision that so many of us have a vested interest in.

4 Likes

On that note, are there language features with future directions alluded to but yet to be designed or implemented which, if they were, could have an outsized impact on design and execution of this vision? Obviously not possible to survey holistically, but if there's possible low-hanging fruit, would be good to know...

2 Likes