Table of Contents

    Book an Appointment

    How Did a Package Manager Upgrade Break Our Expo Monorepo Build?

    While working on an enterprise logistics SaaS platform, our team managed a complex ecosystem comprising a web dashboard, shared business logic utilities and a mobile application. To streamline dependencies and code sharing, we structured this as an expo monorepo. Everything was running smoothly until a routine technical debt sprint where we upgraded our package manager from version 10.22 to 11.5.2.

    Suddenly, our CI/CD pipelines ground to a halt. The failure wasn’t in the build step or a unit test, but during the environment validation phase. Specifically, expo doctor began flagging a failed check that had previously passed without issue. The tool reported that local Expo module directories for Android and iOS were being gitignored.

    In production-grade applications, validation checks like this matter. If native directories for local modules are accidentally ignored, subsequent developers cloning the repository—or CI servers pulling the code to build release artifacts—will silently miss critical native code. This leads to inexplicable runtime crashes and failed builds. We realized we had to deep-dive into how tooling evaluates project boundaries. This challenge inspired this article so other engineering teams can avoid the same configuration pitfalls when scaling their mobile architectures.

    Why Do Local Expo Modules Fail Validation in a Monorepo Architecture?

    Our workspace was designed with a standard monorepo structure, isolating different concerns while sharing a unified node environment. The architecture looked like this:

    /app
    /shared
    /web
    

    The mobile application resided entirely inside the /app directory. To maintain a clean repository, our root .gitignore contained rules to exclude generated directories, environment configurations and the compiled native folders of the Expo prebuild process (specifically app/ios and app/android). Additionally, we utilized local Expo modules located at app/modules/[my-module]/ to encapsulate custom native integrations required by the logistics tracking hardware.

    When you run expo doctor, it performs a health check on the project. One of its crucial responsibilities is ensuring that you haven’t mistakenly told Git to ignore the source code of your custom local modules. If ./modules/my-module/android is ignored, the native build process will fail to link the local module. The problem was that our codebase hadn’t changed—only our package manager did. Yet, the environment validation now perceived our module directories as explicitly ignored.

    What Caused Expo Doctor to Misinterpret the Gitignore Rules?

    Upon reviewing the build logs, we analyzed the exact symptom:

    18/19 checks passed. 1 checks failed. Possible issues detected:
    Use the --verbose flag to see more details about passed checks.
    ✖ Check for common project setup issues
    The "android" and/or "ios" directories (./modules/your-module/[android|ios])
    for local Expo modules are gitignored and they should not be. This is often
    due to overly general gitignore rules.
    Advice:
    Use patterns like "/android" and "/ios" in your .gitignore file to exclude
    only the top-level "android" and "ios" directories and not those in the
    modules directory.
    

    To understand what went wrong, we audited our root .gitignore file. It contained the following application build rules:

    # App builds
    app/ios
    app/android
    

    In standard Git behavior, a rule like app/ios matches the directory app/ios relative to where the .gitignore file is located. However, Node-based CLI tools (like Expo CLI) often rely on third-party JavaScript libraries (such as the ignore package) to simulate Git’s path matching logic. When we upgraded our package manager, the underlying dependency tree resolution and the way symlinks were generated in the workspace shifted slightly.

    Because the local modules were located at app/modules/[my-module]/android, a strict Node-based path resolver running in a modified symlink context started misinterpreting the unanchored app/android rule as a wildcard match for any android folder descending from the app directory boundary. The oversight wasn’t necessarily Git itself, but how JavaScript-based validation tools parsed unanchored directory exclusion rules within nested monorepo symlinks.

    How Did We Diagnose and Evaluate Solutions for the Expo Doctor Gitignore Error?

    When organizations hire software developer teams to build resilient systems, the expectation is that they don’t just patch a problem, but evaluate the architectural implications of the fix. We explored several approaches to resolve this path resolution discrepancy.

    Did We Consider Using Absolute Paths in the Workspace Root?

    Our first thought was to strictly anchor the ignore rules. By changing app/android to /app/android/, we explicitly tell the parser that we only want to ignore the exact android folder at the root of the /app directory, preventing it from recursively matching /app/modules/.../android. This is the cleanest approach that aligns with native Git specifications.

    What About Bypassing Expo Doctor Checks in CI/CD?

    We briefly considered skipping the environment validation in our CI pipeline using environment variables. However, bypassing validation checks defeats the purpose of automated health monitoring. If a developer later accidentally ignored a crucial file, we would miss it. We discarded this idea immediately as it compromises delivery maturity.

    Could Modifying the Package Manager Workspace Resolution Solve It?

    We investigated if we could revert the specific node-linker or symlink behavior in the package manager configuration. While this would solve the immediate symptom, it would lock us out of future performance improvements introduced in the 11.x upgrade. It is better to fix the root cause (ambiguous ignore rules) than to downgrade tooling capabilities.

    How Did We Implement the Final Fix for the Expo Monorepo?

    We proceeded with strict directory anchoring in the root .gitignore and combined it with explicit negation rules to guarantee that local modules remain tracked regardless of how future CLI versions parse the file. Here is the technical fix we applied to the root configuration.

    Original Root Configuration:

    # App builds
    app/ios
    app/android
    

    Corrected Root Configuration:

    # App builds
    # Anchor the paths to prevent recursive matching in subdirectories
    /app/ios/
    /app/android/
    # Explicitly ensure local expo modules are NEVER ignored
    !/app/modules/**/android/
    !/app/modules/**/ios/
    

    By appending the leading slash /, we anchor the rule to the directory of the .gitignore file. The trailing slash / ensures it only matches directories, not files named “android”. The negation rules (!) act as a secondary safety net. After committing these changes, we ran expo doctor across all environments and the validation passed perfectly. We also verified with git check-ignore -v app/modules/my-module/android/build.gradle to ensure Git itself was correctly tracking the local module sources.

    What Are the Key Takeaways for Teams Managing an Expo Monorepo?

    Solving this tooling discrepancy provided several actionable insights that technical leaders should consider when they structure dedicated remote engineering teams.

    • Anchor Your Ignore Rules: Always use leading slashes (e.g., /folder/) in a root .gitignore when you intend to ignore a specific top-level directory. Unanchored rules are the leading cause of accidental file exclusions in large codebases.
    • Understand Tooling Differences: CLI tools rarely use the native Git C-binary to parse ignore rules; they use JavaScript approximations. Symlinks in monorepos can expose edge cases in these parsers.
    • Leverage Negation Rules: For critical infrastructural folders like custom native modules, use Git negation (!) to explicitly enforce inclusion.
    • Do Not Bypass CI Validations: When a tool like expo doctor fails, it is exposing a real underlying fragility. Investigate the root cause rather than suppressing the warning.
    • Monitor Package Manager Upgrades: Upgrades to workspace managers can fundamentally alter how paths and symlinks resolve. Always run a full suite of validation commands post-upgrade.
    • Hire for Architectural Thinking: Resolving issues in nested workspaces requires deep context. When you hire DevOps engineers for CI/CD optimization, ensure they understand the intricacies of Node resolution versus native system resolution.

    Ready to Standardize Your Mobile Monorepo Architecture?

    The shift to advanced monorepo architectures brings immense code-sharing benefits but introduces complex tooling challenges. Ensuring that your validation checks, continuous integration pipelines and dependency managers operate harmoniously requires deep engineering expertise. If your organization wants to hire app developer to create a mobile app that scales reliably or if you need to augment your existing team with pre-vetted remote software developers who understand enterprise project structures, contact us. We provide the structured delivery and technical maturity required to keep your systems robust.

    Social Hashtags

    #ExpoDoctor #ExpoMonorepo #ReactNative #ExpoDev #Gitignore #Monorepo #ReactNativeDevelopment #MobileAppDevelopment #CICD #DevOps #ExpoModules #BuildErrors #SoftwareEngineering #JavaScript #DeveloperTips

    Frequently Asked Questions