Advanced iOS Summer Bundle

3 brand-new books on SwiftUI, Combine and Catalyst — $99.99 for a limited time!

Vapor vs. Kitura: Choosing a Server-Side Swift Framework

If you’re coming from iOS development and considering server-side Swift, one of the first questions you’ll likely ask is “Which framework should I choose, and why?” In this post we’ll compare the two most popular Server-side Swift frameworks: Vapor and Kitura.

5/5 12 Ratings

Version

  • Swift 4.2, Other, Xcode 10

Server-side Swift is an exciting platform that brings the clarity, performance and compiler-driven type safety of Swift to the modern web. Drawn by Swift’s unique strengths, a rich ecosystem of frameworks has developed since Apple announced Swift’s open sourcing. If you’re coming from iOS development and considering server-side Swift, one of the first questions you’ll likely ask is: “Which framework should I choose and why?”

If that sounds like you, read on. In this post, you’ll see a comparison of the two most popular Server-side Swift frameworks: Vapor and Kitura.

When compared with traditional web frameworks for languages such as JavaScript, Ruby and PHP, Vapor and Kitura’s deep Swift-based commonalities are evident and compelling. Both frameworks contribute actively to the Swift community as a whole — especially to the Swift Server Work Group (SSWG).

When viewed side by side, each framework has a distinct personality, philosophy and approach that clearly differentiates it from the other. These differences in perspective and approach will be the main focus of this post. Both Kitura and Vapor are powerful and polished frameworks with a lot to offer. Ultimately, the answer to the question, “Which framework is right for me?” will be based in a secondary question: “Which one best matches my own approach and priorities?” Let’s dive in!

Commonalities

Both Kitura and Vapor share key lessons and organizational practices built up over years of PHP, JavaScript and Ruby web framework development. In particular, both have a recognizable top-level organization that will look familiar to virtually any developer acquainted with the Model View Controller (MVC) pattern. Here’s a side-by-side view of two simple Vapor and Kitura projects:

Both clearly favor separation of concerns by having different sections for views, models and “glue” code. There are additional commonalities like type safety and compilation.

Type Safety

Just as in iOS and macOS, server-side Swift is a type-safe language. Swift’s type safety is enforced by the compiler at a deep level, and in a web development context, this differentiates both Vapor and Kitura from modern frameworks based in JavaScript, Rails, PHP and many other languages.

Swift’s type system can initially feel constricting to developers not used to type-safety requirements. But Swift leads developers to think more precisely. In a server-side context, the end result is web code that’s more immune to many of the most pernicious errors common in other web frameworks.

A great example of how this can be seen in JSON data. In early versions of both platforms, Swift’s type safety was essentially at war with JSON’s malleable typing and its willingness to accept ad hoc properties at any time. This led to laborious and redundant manual code to check, decode and encode JSON in early versions of both frameworks.

Models were especially painful to design and maintain at this stage. For example, here’s a Vapor 2 Model:

import Vapor
import FluentProvider

final class AttachmentInfo: Model {
  
  let storage = Storage()
  private let expirationMinutes = 
    AppSettings.attachmentExpirationMinutes

  struct Properties {
    static let key = "key"
    static let path = "path"
    static let expires = "expires"
  }
  
  var key: String
  var path: String
  var expires: Date
  
  init(key: String, path: String) {
    self.key = key
    self.path = path
    self.expires = 
      Date().addingTimeInterval(expirationMinutes * 60)
  }

  init(row: Row) throws {
    key = try row.get(Properties.key)
    path = try row.get(Properties.path)
    expires = try row.get(Properties.expires)
  }
    
  func makeRow() throws -> Row {
    var row = Row()
    try row.set(Properties.key, key)
    try row.set(Properties.path, path)
    try row.set(Properties.expires, expires)
    return row
  }
}

extension AttachmentInfo: NodeRepresentable {
  func makeNode(in context: Context?) throws -> Node {
    var node = Node([ : ], in: context)
    try node.set(self.idKey, self.id)
    try node.set(Properties.key, key)
    try node.set(Properties.path, path)
    try node.set(Properties.expires, expires)
    return node
  }
}

extension AttachmentInfo: Preparation {
  static func prepare(_ database: Database) throws {
    try database.create(self) { builder in
      builder.id()
      builder.string(Properties.key)
      builder.string(Properties.path)
      builder.date(Properties.expires)
    }
  }
  
  static func revert(_ database: Database) throws {
    try database.delete(self)
  }
}

It’s 78 lines of code — and several not-so-DRY methods — for a Model with just three simple properties. The equivalent early Kitura code suffered from the same linguistic limitations.

This core problem was addressed in Swift 4 with the Codable protocol, which effectively transformed JSON handling from a liability to an asset throughout the Swift platform. To their credit, both Kitura and Vapor aggressively incorporated Codable, removing the need for swaths of verbose code and striking a near-perfect balance between Swift’s inherent type safety and JSON’s flexibility and adaptability. As a result, in Vapor 3, the 78-line model above becomes:

import Vapor

struct AttachmentInfo: Content, Migration {
  let key: String
  let path: String
  let expires: Date

  init(key: String, path: String) {
    self.key = key
    self.path = path
    self.expires = 
      Date().addingTimeInterval(AppSettings.attachmentExpirationMinutes * 60)
  }
}

Kitura 2’s streamlined model is slightly different, but shows nearly identical benefits derived from Codable:

import Foundation

struct AttachmentInfo: Codable {
  var key: String
  var path: String
  var expires: Date

  init(key: String, path: String) {
    self.key = key
    self.path = path
    self.expires = 
      Date().addingTimeInterval(AppSettings.attachmentExpirationMinutes * 60)
  }
}

This is a huge win, and the benefits go well beyond the surface. Both platforms use Codable up and down their stacks, allowing developers to work directly with Swift structs and types, while still providing full flexibility to ingest and output rich JSON data. That’s about as good a definition of “best of both worlds” as I know! :]

The Advantages of Compilation

Server-side Swift web apps are statically compiled. This provides multiple benefits:

  • Compiled web apps are safer by design. There’s significantly less exposure and danger if the only assets exposed are compiled bit code, rather than human-readable source code. This doesn’t give server-side Swift a pass from other security risks, but it’s significant.
  • Compiled apps tend to be more performant relative to their transpiled or just-in-time-compiled counterparts. A series of benchmarks early in server-side Swift’s evolution typically showed order of magnitude-level performance benefits relative to common alternatives. For example, the Vapor team presented this platform comparison shortly after the release of Vapor 1, demonstrating impressive performance even at that early stage:

  • But what if you don’t need screaming speed? Micro-services and other lightweight components written in a server-side Swift framework are typically expected to be exceptionally efficient in their energy and resource use.
    Note: It’s unfortunate that there’s a notable lack of objective benchmarks — especially few since the earliest proof-of-concept days of the platform. In my own experience, Vapor web apps and services my team has delivered to enterprise clients have typically been shown to reduce system load 80% – 90% relative to Node.js-based services they’ve replaced. Obviously, this is no substitute for objective benchmarking, which we hope to see emerge soon.

    Last, it’s important to note that, although Swift on the client side is most typically limited to Apple hardware and OS’s, this limitation doesn’t carry across to Swift on the Server. Thanks to the efforts of Apple and the Swift developer community, server-side Swift can be deployed also on Ubuntu Linux, multiple cloud platforms, and almost anywhere using Docker. This isn’t a competitive advantage, but it’s worth noting that server-side Swift is on par with Rails, JavaScript and PHP web apps in this respect.

Differences

Both Vapor and Kitura implement and extend Swift’s intrinsic benefits in their own specific ways. Each framework has a “flavor” with several aspects that make each framework unique.

Heritage

Kitura has been sponsored and controlled by IBM since its inception. Kitura is fully open sourced under the Apache license, but IBM’s corporate sponsorship and resources are clearly evident throughout the framework. By contrast, Vapor came to life as an independent framework without corporate affiliation or sponsorship. While it picked up its first corporate sponsors shortly afterwards, Vapor’s independence and developer focus clearly show its own approach and personality.

Priorities and Philosophy

The effect of these different lineages can be seen in the differing approaches and priorities of the two frameworks as they’ve evolved and responded to Swift’s rapid evolution. Kitura consistently favors predictability and backwards compatibility. Its API has remained remarkably stable given Swift’s own aggressive evolution during the last few years, and it’s a point of pride for team members that code written in Kitura 1.0 still builds and runs to this day.

Kitura’s emphasis on continuity over newness gives it a somewhat conservative feeling. While this may disappoint some developers, it brings continuity and helpful tools essential in the enterprise, such as on by default health check route that makes it straightforward to monitor Kitura web app uptime and performance under load.

On the other hand, Vapor’s developer-centric roots mean that it tends to move more aggressively whenever new Swift features and technologies are released. Overall, the Vapor API has shown significantly more volatility between each version than Kitura, and both Vapor 2 and 3 (the current version) have featured deep reworkings of both core components and the exposed API.

This has meant that apps developed in one version have typically required significant rewrites to run in the next. Whether this is a pattern or an anti-pattern depends on one’s priorities. In the large and highly active Vapor developer community, these sweeping changes have been generally accepted as the cost of rapid evolution and improvement.

The same difference is reflected in how the two frameworks responded to the release of the highly regarded low-level SwiftNIO framework in early 2018. The Vapor core team integrated it into the then-upcoming version 3 right away! In a 2018 interview with Paul Hudson, Vapor founder and lead developer Tanner Nelson revealed that the framework had anticipated and prepared for this rapid adoption.

Conversely, the Kitura team took a more cautious approach and spent several months stress testing NIO and ensuring that performance edge cases were fully tested and resolved before formally adopting it later that year.

Approach to APIs

A similar difference in approach plays out in the way the two platforms write and expose APIs. Vapor has been “full stack Swift” from the very start. Whether you’re writing routing code, interacting with your data sources, or templating your web pages, you’ll work in Swift.

Vapor APIs are built from the ground up to reflect the best practices of writing Swift code. This makes for a consistent Swift-y experience throughout the platform that’s likely to appeal strongly to iOS developers wanting to extend their Swift expertise to the server. In many cases — such as with Vapor’s native Swift database drivers — this eliminates any need for non-Swift dependencies.

Kitura approaches APIs from a wider industry perspective, in which JavaScript platforms like Node, Express and even Java tools are widely used. The Kitura team has chosen to base many APIs not primarily on Swift standards, but rather on standards from this broader web community. For example, its template language Stencil takes its syntax from the popular Django and Mustache tools, and its overall syntax was modeled on Express, which is used in a wide array of Node.js web frameworks.

This same perspective shows through once more in Kitura’s tendency to use the best available tools for a given task, regardless of their language. This would be an anti-pattern in the Vapor community, where all core stack elements are implemented in Swift. But there’s wisdom in Kitura’s approach that becomes apparent from an enterprise perspective. And experienced web developers will likely appreciate an approach that lets them take advantage of Swift’s best features while also being able to leverage conventions and tools they’ve already mastered elsewhere.

Take a look at the implementation style of both frameworks.

Programming Style

Once more, Vapor is more aggressively Swift-y and leading-edge than Kitura, here.

In its current version 3, Vapor syntax prominently features heavy use of promise-like Futures as a core of the version’s async performance optimizations and its inclusion of SwiftNIO. This, in turn, makes Vapor code more overtly functional in style, with extensive use of nested closures and functionally oriented methods like map() and flatMap() in evidence everywhere.

This tends to give Vapor a distinctively abstract flavor, as code almost universally deals with manipulating, awaiting and reasoning about async futures that may or may not be fulfilled in real time. For example, here’s a simple Vapor route:

func getAllHandler(_ req: Request) throws -> Future<[User]> {
  return User.query(on: req).all()
}

Here’s a more complex route that combines async and functional traits:

func userHandler(_ req: Request) throws -> Future<View> {
  return try req.parameters.next(User.self)
    .flatMap(to: View.self) { user in
      return try user.acronyms
        .query(on: req)
        .all()
        .flatMap(to: View.self) { acronyms in
          let context = UserContext(title: user.name, user: user, acronyms: acronyms)
          return try req.view().render("user", context)
      }
  }
}

In contrast, even though Kitura also leverages NIO and async, it exposes this less in its API. As a result, Kitura coding — and routing in particular — tends to look more “concrete” than Vapor’s.

For example, here’s a sample route in Kitura:

func getEntries(user: UserAuth,
                query: JournalEntryParams?,
                completion: @escaping ([JournalEntry]?, RequestError?) -> Void) {
  JournalEntry.findAll(matching: query, for: user, completion)
}

Performance

How do the two frameworks compare in performance? Unfortunately, as we’ve already seen, this question can’t be objectively answered at this time, as there’s not yet a standardized set of benchmarks we can apply to the two frameworks, and the best benchmarks we currently have come from the early days of both platforms.

Both frameworks have evolved heavily since these early days — investing heavily in core performance optimizations — and community consensus is that the earlier documented performance advantages have only increased with time.

When we compare Kitura and Vapor head to head, we know that both frameworks take heavy advantage of Swift’s most performant aspects, and that both have made excellent use of more modern tools like SwiftNIO. But beyond this, there’s little, if any, objective empirical evidence to prefer one over the other: Both have been extensively battle tested, with very positive subjective reports from the field. But keep your eye on this space… there’s a good chance that you’ll see new sets of benchmarks in the near future!

What’s it like to implement an app with these frameworks?

Implementation and Deployment

One of the really nice things about Kitura’s broader industry focus is that it embraced Docker implementations very early on. This decision has once again provided stability and continuity across Kitura versions. And it means that it’s long been possible to implement Kitura solutions wherever Docker extends.

The Vapor community was initially less enthusiastic about Docker as a deployment target, but with Vapor 3, Docker implementations have become much more common. At this point, both platforms are largely on par in this respect, and it seems clear that streamlining Docker deployment will be central to the future evolution of both platforms.

Extensibility

We’ve focused largely on internals so far. Another big consideration when choosing a web framework is its breadth and extensibility. How readily can you add new integrations and capabilities to it as your project grows?

Kitura benefits from a strong library of packages. Currently, there are over 50 IBM-supported packages. For its part, Vapor provides a wide array of community resources, currently numbering over 100.

In perspective, while both frameworks have done a lot on this front in a short period of time, neither has come close (yet) to achieving the breadth and richness of available packages that competing frameworks have developed over time. By any metric, this is currently a growth pain being experienced by the entire server-side Swift community.

In practical terms, if you’re looking to do something outside the current crop of official Kitura packages or Vapor Community frameworks, you’ll likely have to do some bushwhacking on your own. Depending on the specific problem, solving a case like this at present may mean adapting an existing open-source framework or having to implement a new capability from scratch.

Vapor and Kitura are members of the SSWG helping to steer direction on an initiative to enable future packages to be interchangeable. This means that that new packages built on top of NIO and following common conventions should soon work with both Vapor and Kitura. This, in turn, has the potential to transform the extensibility landscape across the entire server-side Swift landscape very much for the better in the near future.

Which Should You Choose?

By now, it’s likely clear that choosing which framework is right for you comes down to deciding which fits your own coding style and the needs of any specific project.

Here’s a recap of the key comparisons of these two great frameworks:

  • What’s most important to you? Stable, backwards-compatible API’s or early adoption of new Swift technologies as soon as possible after they emerge? If you need to ensure that code you write today will run unaltered as long as possible, Kitura may appeal to you more. If you prioritize maximizing fresh Swift goodness and can accept the cost of potentially significant breaking changes between releases, Vapor’s your likely choice.
  • Do you prefer tools and APIs drawn from the broader web industry, or would you prefer them to maximize Swift sensibilities? If you’re coming from a Rails / JavaScript / PHP perspective and generally like the tools you’ve used, Kitura will likely appeal most. If you’re coming from iOS and native Apple development and don’t have a heavy investment in JavaScript API’s, Vapor’s approach will likely call to you. This same dynamic continues as we consider the tech stacks of each framework. If you know and like common web tools, you’ll likely be happy having non-Swift, industry-standard tools and grammars in your tech stack. Swift purists and iOS developers without deep web tool investments will likely prefer a pure Swift stack top to bottom.
  • What about the API style? If you’re a fan of functional programming and are comfortable with its abstractions, Vapor is likely going to appeal greatly. On the other hand, Kitura’s more traditional approach could be a better match if you prefer your code less abstract and, arguably, simpler to get your head around.
  • How and where do you want to deploy your web apps? The difference between the two is less pronounced here than it has been in the past, but differences in emphasis and support remain. If you happen to have an investment in IBM’s cloud offerings, Kitura’s a clear winner. The Vapor Cloud platform has several attractive features, but is still relatively young with some rough edges remaining. Beyond that, both platforms provide increasingly strong support for Docker and by extension virtually all major cloud platforms.
  • How is the performance? In a word, fantastic. Both frameworks provide exceptionally strong performance and efficiency at scale. Generally, if efficiency or performance are major considerations, this is a potentially strong reason to choose either of these server-side Swift frameworks over other industry competitors. At this point, there just aren’t strong reasons to choose between Kitura and Vapor on this basis.
  • How much functionality do you want to build from scratch? We’ve seen that both Vapor and Kitura have relatively strong sets of third party and extended frameworks available in their respective ecosystems. But neither comes close to what’s available to more mature JavaScript, Ruby, PHP and other frameworks. If you’re looking to add a lot of functionality outside the box of what either platform supports, this is a likely indicator that the project you’re considering isn’t (yet) a great candidate for Server-side Swift.
    • Summing Up

      There’s no obvious winner. And at the end of the day, that’s a great thing. We should appreciate that the Swift community is deep and robust enough to support multiple thriving server-side platforms, each with their distinct approach and advantages. It’s also worth appreciating that both platforms give back to the community by actively contributing to the ongoing evolution of Swift itself.

      Technologically, there’s simply no wrong choice. If you’re looking to dive into server-side Swift, you should take the plunge! The water’s just fine, and both the Vapor and Kitura ends of the pool are great places to swim. :]

      Where to Go From Here?

      Ultimately the choice comes down to your own priorities, needs, and style. I’d strongly encourage you to play with both platforms and decide for yourself. Take a closer look at the resources available on the Vapor and Kitura sites. I also encourage you to consider our Kitura and Vapor books as well as our complete Vapor and Kitura web courses. You can’t go wrong with either. :]

      If you have any questions or comments, join the forum discussion below!)

Average Rating

5/5

Add a rating for this content

12 ratings

Contributors

Comments