The "No module" error in Xcode 15 typically stems from missing or misconfigured header search paths, incorrect build settings for Objective-C bridging, or stale derived data. To resolve this, verify that your target’s Header Search Paths include the correct framework directories, ensure the bridging header is properly referenced if mixing Swift and Objective-C, and clean the project by deleting Derived Data to force a fresh compilation of all modules.
Understanding the Root Cause
When Xcode reports that a module cannot be found, it usually means the compiler cannot locate the necessary header files or the module map that defines the public interface of a framework. This issue has become more prevalent with Xcode 15 due to stricter build system defaults and changes in how Swift Package Manager (SPM) interacts with native Objective-C frameworks. Unlike previous versions, Xcode 15 enforces more rigorous path validation, meaning that relative paths that previously worked might now fail if they are not explicitly marked as recursive. It is crucial to distinguish between two common scenarios: importing a standard Apple framework like Foundation versus importing a third-party CocoaPod or SPM package. The former rarely causes issues unless the deployment target is mismatched, while the latter often fails due to incomplete build phase configurations. If you are working with a mixed-language project, remember that Swift files access Objective-C code via a generated bridging header, but Objective-C files must import headers directly using quotes or angle brackets depending on whether the file is local or part of a framework. Confusing these mechanisms is a primary source of the "No module" error.Verifying Header Search Paths
The most frequent culprit for missing modules is an incorrect configuration in the Header Search Paths build setting. Navigate to your project navigator, select your target, and go to the Build Settings tab. Use the search bar to filter for "Header Search Paths." You will see entries listed under both Debug and Release configurations. Ensure that the paths pointing to your framework’s root directory are included. For example, if you are using a library located in a subdirectory, the path should look something like${PROJECT_DIR}/YourProject/Dependencies/LibraryName. A critical detail often overlooked is the recursion flag. If the headers are nested within subdirectories, you must append ** to the end of the path to indicate that the search should be recursive. Without this flag, Xcode only looks at the immediate directory, leading to unresolved symbol errors.
If you are using CocoaPods, verify that the Pods/Target Support Files/Pods-YourTarget/Pods-YourTarget.debug.xcconfig file is being included. Sometimes, after updating pods, the xcconfig files are not properly linked to the main target, causing the header paths to vanish during compilation. You can check this by ensuring that the Configurations build setting includes the path to your pod xcconfig file.
Cleaning Derived Data and Build Artifacts
Stale build artifacts are a persistent source of intermittent compilation errors in Xcode. When you switch branches, update dependencies, or change build configurations, the derived data may retain references to old module maps that no longer exist or have changed structure. Clearing this data forces Xcode to rebuild its index and re-evaluate all module dependencies. To perform a thorough clean, first quit Xcode completely. Then, navigate to your user home directory and open theLibrary/Developer/Xcode/DerivedData folder. Delete the entire contents of this folder or remove the specific folder associated with your project. Alternatively, you can use the terminal command rm -rf ~/Library/Developer/Xcode/DerivedData/* to clear all derived data safely.
After deleting the derived data, reopen your project in Xcode. Wait for the indexing process to complete, which is indicated by the progress bar in the top right corner of the IDE. Once indexing finishes, attempt to build the project again. In many cases, this simple step resolves false-positive "No module" errors caused by corrupted build caches.
Checking Framework Linking and Build Phases
Even if your header paths are correct, the linker must know where to find the compiled binary of the module. Go to your target’s Build Phases tab and inspect the Link Binary With Libraries section. Ensure that every framework required by your code is listed here. If you are using a static library or a framework bundled in your app, it must be present in this list. For Swift Package Manager packages, verify that the package dependency is correctly added to the target. Sometimes, a package is added to the project level but not assigned to the specific target you are trying to compile. Check the Frameworks, Libraries, and Embedded Content section in Build Settings to ensure the status of the framework is set to Embed & Sign or Do Not Embed appropriately, rather than Optional, which might cause linking failures in certain configurations. If you recently migrated from CocoaPods to SPM or vice versa, ensure that old references have been completely removed. Leftover symlinks or duplicate entries in the link phases can confuse the build system. It is also advisable to runpod install or swift package resolve again to ensure the dependency tree is consistent with your manifest files.
Mixed Language Project Considerations
In projects that combine Swift and Objective-C, the interaction between the two languages requires careful setup. While Swift automatically generates a bridging header for Objective-C imports, Objective-C files do not automatically gain access to Swift symbols unless you create a generated header and import it. However, the reverse is not true; Objective-C files must explicitly import their own headers. If you are seeing errors in Objective-C files regarding Swift modules, ensure that the Defines Module build setting is enabled for any Swift-only targets that need to be accessed from Objective-C. Additionally, check that the Product Module Name is unique and does not conflict with existing framework names. Ambiguity in module naming can lead the compiler to look in the wrong place for definitions. For a deeper dive into troubleshooting connection issues that might indirectly affect build reliability, you might find our guide on Unable to Connect iPhone Xcode on VMware 17 (MacOS Host) helpful, as environment stability plays a role in consistent builds. Similarly, understanding how to debug log outputs can help identify if the error is occurring at runtime rather than compile time, as discussed in Checking Log Console in Xcode for Swift MMKV Issue.Frequently Asked Questions
Why does cleaning Derived Data fix the error?
Cleaning Derived Data removes cached build artifacts and indexes that may have become corrupted or outdated. This forces Xcode to re-index your project and re-evaluate all module dependencies from scratch, eliminating false positives caused by stale references.How do I enable recursive header searching?
In Build Settings, locate the Header Search Paths entry. Click on the value column and add** to the end of your path string. This tells the compiler to search all subdirectories within that path for header files.
What is the difference between #import and @import?
#import is the traditional C-style preprocessor directive used to include header files directly. @import is a modern Clang feature that imports a module directly, leveraging the module map for faster compilation and better encapsulation. Prefer @import when dealing with frameworks.