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.configSearchPathsin both root and sub-package.vscode/settings.jsonfiles to correctly locate the shared.swiftlint.yml. Also, explicitly defineincludedpaths 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
- SwiftLint CLI installed
- SwiftLint extension installed in VSCode or Cursor
Example Project Structure
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.jsonConfiguration Steps
VSCode Settings at the Root Level
Add the SwiftLint config search path to .vscode/settings.json in the root directory:
"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:
included:
  - Domain/Sources
  - Persistent/SourcesWith 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:
"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:
// Root-level settings.json
"swiftformat.configSearchPaths": [".swiftformat"],
// Per-package settings.json
"swiftformat.configSearchPaths": ["../.swiftformat"]If this article helped you, feel free to buy me a coffee ☕️ . For sponsorship inquiries, please check out the details here.