# What Is ModuleScopePlugin in Create React App and How Does It Restrict Imports?

> Understand ModuleScopePlugin in Create React App. Learn how this Webpack plugin restricts imports to the src directory, enforcing project boundaries and improving code organization.

- Repository: [Meta/create-react-app](https://github.com/facebook/create-react-app)
- Tags: internals
- Published: 2026-02-26

---

**ModuleScopePlugin is a custom Webpack resolver plugin in Create React App (CRA) that enforces a strict project boundary by blocking any import that resolves outside the `src/` directory unless explicitly whitelisted.**

Create React App uses `ModuleScopePlugin` (located in [`packages/react-dev-utils/ModuleScopePlugin.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-dev-utils/ModuleScopePlugin.js)) to guarantee that application code remains isolated within the `src/` folder. This prevents accidental dependencies on files scattered across the repository root or other arbitrary locations, ensuring consistent builds and predictable module resolution.

## What Is ModuleScopePlugin?

`ModuleScopePlugin` is a Webpack plugin that intercepts module resolution at the compiler level. It was introduced in the `facebook/create-react-app` monorepo to solve a specific problem: developers accidentally importing configuration files, build scripts, or shared utilities located outside the `src/` directory, which breaks the encapsulation of the React application.

The plugin operates as a resolver hook in Webpack’s **enhanced-resolve** pipeline. When Webpack attempts to resolve an import statement, `ModuleScopePlugin` examines both the **issuer** (the file containing the import) and the **requested** file path before allowing the resolution to proceed.

## How ModuleScopePlugin Restricts Imports

The restriction logic follows a two-step validation process defined in [`packages/react-dev-utils/ModuleScopePlugin.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-dev-utils/ModuleScopePlugin.js).

### The Issuer Check

First, the plugin verifies whether the file performing the import (the issuer) resides within the configured source directories (typically `paths.appSrc` which maps to `src/`). If the issuer is **outside** these directories, the plugin immediately returns without enforcing any restrictions, allowing build scripts and configuration files at the project root to import freely.

### The Request Validation

If the issuer is inside `src/`, the plugin then checks the requested file path:

1. If the request resolves to a location **inside** any configured `appSrc` directory, resolution proceeds normally.
2. If the request resolves **outside** all `appSrc` directories and is not present in the `allowedFiles` or `allowedPaths` sets, the plugin **throws a blocking error**.

The error message explicitly states:

```

You attempted to import ../../config which falls outside of the project src/ directory.
Relative imports outside of src/ are not supported.
You can either move it inside src/, or add a symlink to it from project's node_modules/.

```

This error originates from lines 66-92 in [`ModuleScopePlugin.js`](https://github.com/facebook/create-react-app/blob/main/ModuleScopePlugin.js), where the plugin constructs the error using the relative path information and resolution context.

## ModuleScopePlugin Configuration in CRA

The plugin is instantiated in [`packages/react-scripts/config/webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js) at line 339:

```javascript
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson])

```

This configuration establishes two critical parameters:

- **`paths.appSrc`**: Defines the primary source directory (usually `./src`)
- **`allowedFiles` array**: Contains `paths.appPackageJson` (the project's [`package.json`](https://github.com/facebook/create-react-app/blob/main/package.json)), permitting imports like `import packageJson from '../package.json'` despite [`package.json`](https://github.com/facebook/create-react-app/blob/main/package.json) residing at the repository root

The plugin applies to both development and production builds, ensuring consistent enforcement across all Webpack configurations generated by CRA.

## What Imports Are Blocked vs. Allowed

Understanding the boundary conditions helps developers structure their projects correctly.

### Allowed Imports

Any import where both the issuer and target reside within `src/`:

```javascript
// src/components/App.js
import Helper from '../utils/helper';  // ✅ Allowed: both files under src/
import logo from './logo.svg';         // ✅ Allowed: relative import within src/

```

Imports from `node_modules` are also permitted because Webpack resolves these through its standard node_modules resolution algorithm before `ModuleScopePlugin` validates the result.

### Blocked Imports

Any attempt to import files located outside `src/` from within `src/`:

```javascript
// src/components/App.js
import config from '../../config';     // ❌ Blocked: resolves to repository root
import rootUtil from '../..';         // ❌ Blocked: outside src/ boundary

```

Attempting to build this code triggers the descriptive error from [`ModuleScopePlugin.js`](https://github.com/facebook/create-react-app/blob/main/ModuleScopePlugin.js), halting the compilation process.

## How to Whitelist Files Outside src/

While CRA strongly recommends moving all application code into `src/`, the plugin provides escape hatches for edge cases.

### Adding Files to allowedFiles

You can permit specific files by modifying the plugin instantiation in [`webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/webpack.config.js) (requires ejecting or using a tool like `react-app-rewired`):

```javascript
const path = require('path');

new ModuleScopePlugin(paths.appSrc, [
  paths.appPackageJson,
  path.resolve(__dirname, '../../shared/constants.js')  // Whitelisted file
])

```

This allows `import constants from '../../shared/constants'` from within `src/` despite the file residing outside the source directory.

### Adding Directories to allowedPaths

The plugin also accepts an `allowedPaths` option (distinct from `allowedFiles`) that permits entire directories. This is handled internally in the plugin's resolution logic and can be passed as a third argument or configured through the plugin's options object depending on the CRA version.

## Summary

- **ModuleScopePlugin** is a Webpack resolver plugin in [`packages/react-dev-utils/ModuleScopePlugin.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-dev-utils/ModuleScopePlugin.js) that enforces the `src/` directory boundary.
- It blocks any import that resolves outside `src/` unless the file is explicitly whitelisted in `allowedFiles` or `allowedPaths`.
- The plugin is configured in [`packages/react-scripts/config/webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js) with `new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson])`.
- Attempting to import from outside `src/` produces a descriptive error suggesting moving the file into `src/` or creating a symlink in `node_modules/`.

## Frequently Asked Questions

### Can I disable ModuleScopePlugin in CRA without ejecting?

Disabling `ModuleScopePlugin` without ejecting requires using a customization tool like `react-app-rewired` or `craco`. You would modify the Webpack configuration to remove the plugin from the `resolve.plugins` array. However, disabling it removes the safety guard that keeps your application code isolated, potentially leading to brittle dependencies on files outside your source tree.

### Why does CRA restrict imports outside the src/ directory?

The restriction ensures that all application logic, assets, and components reside in a single, predictable location. This encapsulation prevents accidental dependencies on build configuration files, documentation, or server-side code that may exist at the repository root. It also simplifies future migrations, refactoring, and code splitting since the bundler can assume all source code lives under `src/`.

### How do I import from a shared directory outside src/?

The recommended approach is to move the shared code into `src/` or publish it as an npm package. If neither is feasible, you can whitelist specific files by adding them to the `allowedFiles` array in the `ModuleScopePlugin` constructor within [`webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/webpack.config.js) (requires ejecting or using a rewiring tool). Alternatively, create a symlink from `node_modules/` pointing to the external directory, which bypasses the plugin's checks since `node_modules` imports are handled separately.

### Does ModuleScopePlugin affect imports from node_modules?

No, `ModuleScopePlugin` does not block imports from `node_modules`. The plugin specifically checks if the requested file falls outside the configured `appSrc` directories, but it runs after Webpack's standard resolution for `node_modules`. Since packages in `node_modules` are resolved through a different mechanism and are considered external dependencies, they bypass the src/ boundary check entirely.