# How Image and Asset Loading Works in Create React App

> Discover how Create React App handles image and asset loading using webpack. Optimize your app's performance with efficient URL generation and learn about the public folder for static files.

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

---

**Create React App uses webpack to automatically process imported assets from the `src/` directory into optimized, cache-friendly URLs while providing a `public/` folder escape hatch for static files that bypass the build system entirely.**

Image and asset loading in Create React App (CRA) is handled by an integrated webpack configuration that transforms imported files into URLs your application can reference at runtime. According to the facebook/create-react-app source code, the build system distinguishes between two distinct asset pathways: files imported from JavaScript or CSS in the `src/` folder, which are processed through webpack loaders, and files placed in the `public/` folder, which are copied verbatim to the output directory.

## The Two Asset Pathways in Create React App

CRA implements a dual-path architecture for handling static assets:

**`src/` imports (webpack-processed):** When you import an image, font, or video from within your JavaScript or CSS, webpack applies asset module rules defined in [`packages/react-scripts/config/webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js). These files receive content hashing, potential inlining for small assets, and are emitted to `static/media/`.

**`public/` folder (static copy):** Files placed in the `public/` directory bypass webpack entirely. They are copied unchanged to the build output and accessed via the `%PUBLIC_URL%` placeholder or `process.env.PUBLIC_URL`. This approach is useful for files that need to retain exact names, such as [`manifest.json`](https://github.com/facebook/create-react-app/blob/main/manifest.json) or [`robots.txt`](https://github.com/facebook/create-react-app/blob/main/robots.txt).

## Importing Assets from the src Directory

### Webpack Asset Module Configuration

In [`packages/react-scripts/config/webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js), CRA configures webpack's asset modules to handle standard image formats. The configuration uses `type: 'asset'` for files matching `/\.(bmp|gif|jpe?g|png)$/i`:

```javascript
// From webpack.config.js (simplified)
{
  test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
  type: 'asset',
  parser: {
    dataUrlCondition: {
      maxSize: imageInlineSizeLimit,
    },
  },
}

```

This rule instructs webpack to automatically determine whether to inline the asset as a base64 data URL or emit it as a separate file based on the `imageInlineSizeLimit` threshold.

### Inline vs Emitted Files: The 10KB Threshold

CRA sets a default `imageInlineSizeLimit` of **10,000 bytes** (10 KB) in [`packages/react-scripts/config/webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js). This threshold determines asset handling:

**Files ≤ 10 KB:** Webpack inlines the asset as a base64-encoded data URL directly into your JavaScript bundle. This eliminates an HTTP request but increases bundle size.

**Files > 10 KB:** Webpack treats the asset as `asset/resource`, emitting it to the build output with a content hash for cache busting. The import resolves to a URL like `static/media/logo.3d5f1c.png`.

The output filename pattern is configured via `output.assetModuleFilename`:

```javascript
// webpack.config.js
output: {
  assetModuleFilename: 'static/media/[name].[hash][ext]',
}

```

### SVG Special Handling with SVGR

SVG files receive unique treatment in CRA. The webpack configuration in [`packages/react-scripts/config/webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js) processes SVGs through two loaders:

1. **`@svgr/webpack`**: Converts the SVG into a React component that you can import as a named export
2. **`file-loader`**: Emits the SVG file to `static/media/` and provides the URL as the default export

This dual export pattern allows flexible usage:

```javascript
import { ReactComponent as Logo } from './logo.svg';
import logoUrl from './logo.svg';

// Use as React component
<Logo width={120} height={30} title="My Logo" />

// Use as image URL
<img src={logoUrl} alt="Logo" />

```

## Using the Public Folder for Static Assets

The `public/` folder serves as an escape hatch for files that must retain exact filenames or exist outside the module system. According to [`docusaurus/docs/using-the-public-folder.md`](https://github.com/facebook/create-react-app/blob/main/docusaurus/docs/using-the-public-folder.md), files in this directory are copied verbatim to the build output without processing.

### Referencing Public Assets in HTML

Use the `%PUBLIC_URL%` placeholder in [`index.html`](https://github.com/facebook/create-react-app/blob/main/index.html) or other HTML files:

```html
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />

```

During the build, CRA replaces `%PUBLIC_URL%` with the appropriate absolute or relative path based on your `homepage` configuration.

### Referencing Public Assets in JavaScript

Access the public folder path at runtime using `process.env.PUBLIC_URL`:

```javascript
function Footer() {
  return (
    <img 
      src={process.env.PUBLIC_URL + '/images/footer-logo.png'} 
      alt="Footer logo" 
    />
  );
}

```

**Important limitation:** Files in `public/` do not receive content hashing. You must manually implement cache busting (e.g., versioned filenames like `logo-v2.png`) when updating these assets.

## Asset Loading in CSS and SCSS Files

When you reference assets from CSS, Sass, or Less files, the **`css-loader`** resolves `url()` statements as module dependencies. This means the same webpack asset rules apply to images referenced in stylesheets.

In [`packages/react-scripts/config/webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js), the style loader chain includes `css-loader` configured to handle asset URLs:

```css
/* src/App.css */
.hero {
  /* This resolves through webpack and emits to static/media/ */
  background-image: url('./assets/hero-bg.jpg');
}

```

The asset is processed according to the 10 KB threshold: small images inline as data URLs, larger ones emit to `static/media/` with content hashes.

## Key Configuration Files and Implementation Details

The asset handling system in CRA is defined across several configuration files in `packages/react-scripts/config/`:

| File | Purpose | Asset-Related Configuration |
|------|---------|----------------------------|
| **[`webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/webpack.config.js)** | Core webpack configuration | Asset module rules (lines 80-102), `imageInlineSizeLimit` (lines 64-66), `output.assetModuleFilename` (lines 226-229), SVGR loader configuration |
| **[`paths.js`](https://github.com/facebook/create-react-app/blob/main/paths.js)** | Filesystem path resolution | Defines `appPublic`, `appBuild`, and `publicUrlOrPath` used for output locations |
| **[`env.js`](https://github.com/facebook/create-react-app/blob/main/env.js)** | Environment variable injection | Handles `PUBLIC_URL` and `process.env.PUBLIC_URL` resolution |
| **`babel-plugin-named-asset-import`** | Babel plugin | Enables the `import img from './file.png'` syntax by transforming imports |

The `babel-plugin-named-asset-import` package specifically enables the ergonomic import syntax by ensuring that default imports from asset files resolve to their URLs or components.

## Summary

- **Webpack-powered imports**: Files imported from `src/` are processed through asset modules 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 automatic inlining for assets under 10 KB and hashed filenames for larger files in `static/media/`.
- **Dual-path SVG support**: SVG files are processed by both `@svgr/webpack` (for React component imports) and `file-loader` (for URL imports), enabling flexible usage patterns.
- **Public folder escape hatch**: The `public/` directory bypasses webpack entirely; files are copied verbatim and accessed via `%PUBLIC_URL%` or `process.env.PUBLIC_URL` without content hashing.
- **CSS integration**: The `css-loader` resolves `url()` references in stylesheets through the same asset pipeline, ensuring consistent hashing and optimization across JavaScript and CSS.
- **Configuration architecture**: Asset handling is centralized in [`webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/webpack.config.js) with supporting logic in [`paths.js`](https://github.com/facebook/create-react-app/blob/main/paths.js), [`env.js`](https://github.com/facebook/create-react-app/blob/main/env.js), and `babel-plugin-named-asset-import`.

## Frequently Asked Questions

### What is the file size limit for inlining images in Create React App?

Create React App uses a **10 KB (10,000 bytes)** threshold defined by `imageInlineSizeLimit` in [`packages/react-scripts/config/webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js). Images imported from `src/` that are smaller than this limit are automatically converted to base64 data URLs and inlined into your JavaScript bundle, while larger files are emitted to `static/media/` with content hashes for optimal caching.

### How do I import an SVG as a React component in CRA?

You can import SVG files as React components using the named export syntax provided by `@svgr/webpack`. Write `import { ReactComponent as Logo } from './logo.svg';` to receive a ready-to-use React component that accepts props like `width`, `height`, and `title`. You can simultaneously import the same file as a URL using the default import syntax if you need both the component and the file reference.

### What is the difference between putting assets in src versus public?

Assets placed in `src/` are processed by webpack through the asset module system defined in [`packages/react-scripts/config/webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js), receiving benefits like automatic optimization, content hashing for cache busting, and potential inlining for small files. Assets in `public/` bypass webpack entirely and are copied verbatim to the build output; they retain original filenames but must be referenced using `%PUBLIC_URL%` or `process.env.PUBLIC_URL`, and you must manually handle cache invalidation when updating them.

### How does Create React App handle assets referenced in CSS files?

When you use `url()` in CSS, SCSS, or Less files, the `css-loader` resolves these references as module dependencies and passes them through the same webpack asset pipeline used for JavaScript imports. This means images referenced from stylesheets are subject to the same 10 KB inlining threshold and content hashing rules, emitting to `static/media/` when they exceed the size limit, ensuring consistent optimization across your entire application.