Linting vs Formatting: A Swift Guide — Part 2

Linting vs Formatting: A Swift Guide — Part 2

Aside: I ran a workshop for try! Swift World on this subject. If interested, the resources are freely available including a guide that you can follow!


This is part 2/2 of a series on linting and formatting. Where part 1 was focused on the “why,” this part will provide an opinionated take on the “what and how” and will therefore be more practical.

With the background thoughts out of the way in part 1 (including specifics about the differences between linting and formatting), let’s dig into some tooling and how to set them up. This will help keep your code clean in terms of style and even provide a second set of eyes for your code in some cases.

A Recommended Setup

Having set this up several times, I have been tweaking and improving a linting and formatting setup for Apple platform apps (iOS, watchOS, etc.). Ultimately, I think I have found a pretty good setup for these guardrails that help me ship with more confidence.

From a high level, the below setup runs an auto code style formatter locally when running tests and a linter in a continuous integration (CI) environment like GitHub Actions, which auto-comments violations on pull requests (PRs). More specifics below.

Note: example config files and an example app may be found here.


The below uses GitHub Actions for CI. The setup is similar if you use something else like CircleCI or Bitrise.

Use SwiftLint in CI. SwiftLint does generate a Swift abstract syntax tree (AST) to use for analysis, so integrating it locally in Xcode would increase the build time slightly. Integrating it in CI moves that extra processing out of your local dev flow. Also, depending on when you add this to your project and how many warning you have in your app, this can add a lot of noise to your Xcode project since violations wouldshow up as in-line warnings too.


Use SwiftFormat locally via your test target to run only when you run tests and add a check to your CI system. If you ran the formatter on the main app’s target (aka every time you built the app), you would lose the undo history which is a bit annoying. Integrating it like this will reduce that unfortunate side effect. This also has the added side benefit of encouraging you to run your tests 😉.

An Overview of Notable Tools






Home grown style check



Additional thoughts

There is a lot to this subject (hence breaking this up into two parts), and I realize this setup is opinionated. More important than doing things just like described here, do what is best for your app and company. Having these tools in place in some form is better than not and it doesn’t take much to set them up!

Thanks for reading, and feel free to reach out on Twitter — cheers!

rss facebook twitter github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora