🔑 Fixing SwiftLint Configuration Not Working in Monorepo Projects

TL;DR: SwiftLint may fail to apply lint rules in monorepo setups when packages are opened individually in VSCode or Cursor. To fix this, configure swiftlint.configSearchPaths in both root and sub-package .vscode/settings.json files to correctly locate the shared .swiftlint.yml. Also, explicitly define included paths in the config file (wildcards won’t work) to ensure proper linting across all modules.

Background

When managing Swift projects using a monorepo structure, developers often create a single .swiftlint.yml configuration file in the root directory. However, when opening the project root or a specific Package directory in VSCode or Cursor, SwiftLint may fail to load the configuration properly, causing lint rules to be ignored. This article explains how to correctly configure SwiftLint in a monorepo setup to ensure linting works as expected.

Prerequisites

Environment Requirements

Example Project Structure

Bash
MyProject/                  
├── .swiftlint.yml          // Root-level SwiftLint config
├── .vscode/settings.json   // Root-level VSCode settings
├── Domain/
   └── Package.swift
   └── .vscode/settings.json
└── Persistent/
    └── Package.swift
    └── .vscode/settings.json

Configuration Steps

VSCode Settings at the Root Level

Add the SwiftLint config search path to .vscode/settings.json in the root directory:

JSON
"swiftlint.configSearchPaths": [".swiftlint.yml"]

.swiftlint.yml Configuration Notes

The included section must explicitly specify all lint target directories. Wildcards are not supported, which is a common cause of misconfiguration:

YAML
included:
  - Domain/Sources
  - Persistent/Sources

With this setup, SwiftLint will correctly lint the specified directories when opening the full MyProject directory.

VSCode Settings for Each Package

If you often open individual package directories like Domain/ or Persistent/ for development, add the following configuration in each package’s .vscode/settings.json:

JSON
"swiftlint.configSearchPaths": ["../.swiftlint.yml"]

This allows SwiftLint to locate and apply the shared configuration file from the parent directory, even when working inside sub-packages.

SwiftFormat Configuration

SwiftFormat follows a similar configuration pattern but does not require specifying target directories inside the config file. Only the search path needs to be set:

JSON
// Root-level settings.json
"swiftformat.configSearchPaths": [".swiftformat"],

// Per-package settings.json
"swiftformat.configSearchPaths": ["../.swiftformat"]
Weekly Swift & SwiftUI highlights!