Open-source project
mxcl/PromiseKit avatar
mxcl/PromiseKit

PromiseKit: promises for Swift and Objective-C, and where they still fit

Promises for Swift & ObjC.

14,219 stars1,458 forksSwiftMIT

At a glance

What is it?
PromiseKit adds promise chaining to Swift and Objective-C projects that cannot or will not move to async/await. The README shows a complete implementation with Objective-C bridging and Apple framework extensions, but the project itself points elsewhere for new code.
Who is it for?
Adopt PromiseKit when you maintain a Swift or Objective-C codebase that already depends on it, or when you need promise chaining in Objective-C where async/await is not an option. Do not adopt it for a new Swift 5.5+ project: the README itself points to Async+ as a port of PromiseKit's patterns to async/await.
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 118 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 September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem PromiseKit solves, and who is still holding the problem

Callback-based asynchronous code in Swift and Objective-C nests. A network call that needs a decode step, a UI update and a cleanup step becomes a pyramid, and error handling gets duplicated at every level. PromiseKit models an asynchronous operation as a value you can chain: `then`, `map`, `done`, `catch`, `ensure`. The README's opening example fetches an image and a location concurrently with `when(fulfilled:)`, then updates an image view and a label in one `done` block, hides the network activity indicator in `ensure`, and handles failure in `catch`. That is the whole pitch, and it is a real one for anyone who has written the nested version.

The audience is narrower than it was. The README states that as of Swift 5.5 the language has built-in concurrency with async/await, and it points readers to Async+, described as a port of PromiseKit's most useful patterns to that paradigm. So the project is not pretending to be the future of asynchronous Swift. It remains a complete promise implementation for any platform with a `swiftc`, with Objective-C bridging that async/await does not offer, and with extensions that convert most of Apple's APIs to promises. If your codebase is Objective-C, or mixed, that bridging is the reason to be here.

How PromiseKit chains work and what the extensions add

The core is a promise type plus a set of combinators. `firstly` starts a chain, `then` sequences work that itself returns a promise, `map` transforms a value, `done` terminates a successful chain, `catch` terminates a failed one, and `ensure` runs regardless of outcome. `when(fulfilled:)` joins several promises and resolves only when all succeed, which is what the README example uses to run an image fetch and a location request in parallel.

The part that saves the most typing is the extension layer. The README describes it plainly: promises are only as useful as the asynchronous tasks they represent, so the project converted almost all of Apple's APIs to promises. The default CocoaPod ships promises plus extensions for Foundation and UIKit. Everything else is a subspec, so `PromiseKit/MapKit` gives you `MKDirections().calculate().then { }` and `PromiseKit/CoreLocation` gives you `CLLocationManager.requestLocation().then { }`. Each extension lives in its own repository under the PromiseKit organization rather than inside this one.

Networking is the common entry point, and the README documents a `URLSession` path with a `.validate()` step that converts HTTP failures such as 404s into errors the chain can catch. That detail matters more than it looks: without validation, a 404 resolves as a successful promise carrying an error page, and your `catch` block never runs.

Installing PromiseKit with CocoaPods and writing a first chain

The README's Quick Start is a Podfile. Add the pod inside your target and run your normal `pod install`:

ruby
use_frameworks!

target "Change Me!" do
  pod "PromiseKit", "~> 8"
end

After `pod install`, the default pod gives you promises plus the Foundation and UIKit extensions. If you want no extensions at all, the README shows the CorePromise subspec instead:

ruby
pod "PromiseKit/CorePromise", "~> 8"

The README notes that Carthage installations come with no extensions by default, so a Carthage user gets the core and adds extension repositories by hand. For Carthage, SwiftPM and Accio, the README defers to the Installation Guide in Documentation/Installation.md rather than repeating the steps.

For a first chain, the README's networking example is the shortest complete one. It validates the response, decodes it, and handles both outcomes:

swift
firstly {
    URLSession.shared.dataTask(.promise, with: try makeUrlRequest()).validate()
}.map {
    try JSONDecoder().decode(Foo.self, with: $0.data)
}.done { foo in
    //…
}.catch { error in
    //…
}

What you should see is the `done` block running with a decoded value on success, and the `catch` block running with an error on a failed request or a decoding failure. The README does not show the body of `makeUrlRequest()` in this snippet beyond the fact that it throws and returns a `URLRequest`.

Where PromiseKit is the wrong tool now

The honest limitation is stated by the project itself. Swift 5.5 added async/await, and the README directs readers to Async+ for a port of PromiseKit's most useful patterns. If you are starting a Swift project today and your deployment target supports it, adding a promise library means adding a dependency, a vocabulary and a migration path you will eventually pay for. Native concurrency also composes with the rest of the language in ways a library cannot.

There is a second constraint in the README: PromiseKit 8 supports recent Xcodes, 13 and later, and some podspecs were dropped as a result. The README says pull requests are welcome on that point, which is a polite way of saying the older podspec coverage is gone. If your build machine is pinned to an older Xcode, PromiseKit 8 is not the branch for you, and the README points to PromiseKit 6, 5 and 4 for Xcode 8.3 through 10.0 and the Swift 3.x and 4.x line. Those are separate maintenance tracks, not a single version that spans everything.

The third limitation is structural rather than technical. Extensions live in separate repositories under the PromiseKit organization, so a bug or a missing API in the MapKit extension is not fixed in this repository. You are adopting a family of packages, not one.

PromiseKit against plain async/await and against Async+

The direct comparison is with Swift's own async/await, because that is the alternative the README names. The difference is not cosmetic. Async/await is a language feature: the compiler understands suspension points, and there is no chain object to thread through your code. PromiseKit is a library: the chain is a value, and you can pass a promise around, store it, and attach handlers later. That property is why Objective-C code can use PromiseKit at all, and why the README can claim excellent Objective-C bridging as a differentiator. Async/await has no equivalent for Objective-C.

Async+ is the other comparison, and it is a different kind of thing. The README describes it as a port of PromiseKit's most useful patterns to the async/await paradigm, not as a replacement library that keeps the promise API. So the choice is between keeping promise chaining and moving the patterns you like onto native concurrency. If you have a large Objective-C surface, Async+ does not solve your problem and PromiseKit does. If you are all-Swift and modern, Async+ is the direction the README itself points to.

Maintenance, licence and what a version bump costs

The repository is not archived, and the last push was on 2026-06-03. The most recent release listed is 8.2.0 from 2025-01-16, preceded by 8.1.2 in 2024-06-03 and 8.1.1 in 2023-08-27. That is a slow release cadence with continued repository activity, which is a normal shape for a mature library whose API surface has stopped growing.

Upgrade cost is dominated by the version tracks rather than the version numbers. Moving from PromiseKit 6 to 8 is not a patch bump: 8 dropped older Xcodes and some podspecs, and the README treats 6, 5 and 4 as the line for Xcode 8.3 through 10.0. If your project is on an old toolchain, the upgrade is a toolchain project first and a library upgrade second. The README also notes that the default pod pulls in Foundation and UIKit extensions, so a version bump can change your dependency surface if you rely on the default rather than CorePromise.

The licence is MIT, per the repository and the badge in the README. MIT is permissive and places few conditions on redistribution, but this is not legal advice, and a project that offers commercial support through TideLift may attach separate terms to that support. Read the LICENSE file and any support agreement before you assume the two are the same thing.

Editorial conclusion

Adopt PromiseKit when you maintain a Swift or Objective-C codebase that already depends on it, or when you need promise chaining in Objective-C where async/await is not an option. Do not adopt it for a new Swift 5.5+ project: the README itself points to Async+ as a port of PromiseKit's patterns to async/await. Before committing, verify the Podfile subspecs you actually need (the default pod brings Foundation and UIKit extensions, CorePromise brings none), confirm which Xcode version your build uses, since PromiseKit 8 supports Xcode 13 and later and some podspecs were dropped, and check the Documentation/Installation.md guide for the package manager you use, because the README only shows the CocoaPods path in full.

Frequently asked questions

What is PromiseKit used for?

It provides promises for Swift and Objective-C so asynchronous work can be chained with then, map, done, catch and ensure instead of nested callbacks. It also ships extensions that convert most of Apple's APIs, such as URLSession and CLLocationManager, into promises.

Does PromiseKit work with async/await?

The README states that Swift 5.5 added built-in concurrency with async/await and points readers to Async+, described as a port of PromiseKit's most useful patterns to that paradigm. PromiseKit itself remains a separate promise implementation rather than a wrapper over async/await.

Should I use PromiseKit instead of callbacks in Swift?

The README frames the benefit as clearer, more readable code, and its examples replace nested completion handlers with a single chain that has one catch block for errors. For new Swift code on a modern toolchain, the README itself points to async/await instead.

What does PromiseKit's when(fulfilled:) do?

It joins several promises and resolves only when all of them succeed, which is how the README runs an image fetch and a location request in parallel before a single done block. The README does not document a race combinator.

Official sources

  1. Issues
  2. License: MIT
  3. mxcl/PromiseKit on GitHub
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mxcl-promisekit.svg)](https://hysenlabs.com/projects/mxcl-promisekit)