How to Fix: [turbopack]: Can’t specify issuer with @svgr/webpack loader, causes invalid url transformation in css
Turbopack currently breaks a common SVGR setup in Next.js: when you try to scope @svgr/webpack with an issuer rule so only JavaScript and TypeScript imports become React components, CSS url() imports can still be transformed incorrectly. The result is a subtle but damaging asset pipeline bug: SVGs referenced from stylesheets stop behaving like file URLs and get treated like component-oriented module imports instead.
Understanding the Root Cause
In a typical webpack configuration for Next.js, developers use @svgr/webpack to turn SVG files imported from React code into components:
import Logo from './logo.svg'
At the same time, they still want this to work inside CSS:
background-image: url('./logo.svg');
Those are two different use cases and require two different behaviors:
- JS/TS import → transform the SVG into a React component via
@svgr/webpack - CSS url() → keep the SVG as a static asset URL
The standard fix in webpack is to restrict the SVGR loader with an issuer condition, usually something like:
issuer: /\.[jt]sx?$/
That tells webpack: only apply this loader when the SVG is imported by JavaScript or TypeScript files, not by CSS.
The bug appears with Turbopack in the Next.js dev server. Turbopack does not currently honor this loader isolation in the same way, so the SVG rule can affect stylesheet-driven asset resolution. Once that happens, an SVG referenced through url() may be passed through the wrong transformation pipeline, producing an invalid result for CSS asset loading.
In short, the root cause is a mismatch between webpack loader rule expectations and Turbopack’s current handling of issuer-based conditions for SVG imports.
Step-by-Step Solution
Until Turbopack fully supports this pattern, the safest fix is to avoid relying on issuer-based SVGR separation during Turbopack development. Use one of these practical workarounds.
Option 1: Use SVG components only from a dedicated resource query
This is the cleanest workaround because it makes the import intent explicit. React component SVGs use ?component, while CSS and regular asset imports keep normal file behavior.
Update next.config.js or next.config.mjs:
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
resourceQuery: /component/,
use: ['@svgr/webpack'],
})
return config
},
}
module.exports = nextConfig
Then import SVGs as React components only when needed:
import Logo from './logo.svg?component'
export default function Header() {
return <Logo />
}
And keep CSS unchanged:
.hero {
background-image: url('./logo.svg');
}
Why this works: resourceQuery creates an explicit split between component usage and asset usage, avoiding ambiguous loader application.
Option 2: Keep SVG files in public/ when used by CSS
If an SVG is only needed in stylesheets, move it into the public directory and reference it with a root-relative path.
public/icons/pattern.svg
.banner {
background-image: url('/icons/pattern.svg');
}
This bypasses the module loader pipeline entirely for that asset, which avoids Turbopack’s problematic transformation path.
Option 3: Disable Turbopack during development if you depend on issuer-based SVG rules
If your project already relies heavily on the classic webpack pattern and changing imports is too disruptive, use the standard dev server until the bug is fixed upstream.
next dev
Instead of:
next dev --turbo
Or update your package script:
{
"scripts": {
"dev": "next dev"
}
}
This restores expected webpack rule behavior, including issuer-aware loader scoping.
Recommended project pattern
For teams that need both component SVGs and CSS file URLs, use this convention:
- React component SVGs:
icon.svg?component - CSS/background SVGs: plain
.svgfiles or files served frompublic/
That avoids hidden coupling between asset consumers and loader rules.
Example complete setup
const nextConfig = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
oneOf: [
{
resourceQuery: /component/,
use: ['@svgr/webpack'],
},
],
})
return config
},
}
module.exports = nextConfig
Example component import:
import SearchIcon from './search.svg?component'
export function SearchButton() {
return (
<button type="button">
<SearchIcon />
Search
</button>
)
}
Example stylesheet:
.searchBox {
background: url('./search-bg.svg') no-repeat center;
}
Common Edge Cases
- SVG imported both in CSS and React from the same path: if one import expects a URL and another expects a component, the build can become inconsistent unless you separate them with
?componentor different file locations. - Using App Router with mixed client/server components: SVGR output is still a React component module, so make sure it is consumed in places where that module type is valid.
- Third-party packages importing SVGs internally: if a dependency assumes webpack-specific behavior, Turbopack may expose differences more quickly than a standard webpack dev build.
- CSS Modules and global CSS: both can hit the same bug because the problem is not CSS Modules specifically; it is the asset resolution path for
url(). - Production vs development mismatch: you may only see this during Turbopack-powered development. Production builds can behave differently if they use a different bundling path, so always test both.
- Overlapping custom rules: if you already have another loader for images or asset modules, adding SVGR without explicit separation can create conflicting transformations.
FAQ
Why does issuer work in webpack but fail with Turbopack here?
Because Turbopack does not yet fully match webpack’s loader-rule behavior for this case. The issue specifically shows that issuer-based scoping is not reliably preventing CSS-triggered SVG imports from entering the SVGR path.
Is this an @svgr/webpack bug?
Not primarily. @svgr/webpack is doing what it is supposed to do when the loader is applied. The bug is that the loader is being applied in a context where it should have been excluded, which points to the bundler integration path rather than SVGR itself.
What is the best long-term pattern for Next.js projects using SVGs?
The most robust pattern is to make intent explicit: use resource-query based imports like ?component for React components, and keep stylesheet assets as plain URLs or files under public/. That scales better across bundlers and avoids relying on nuanced rule matching.
If you want the least risky immediate fix for this issue, avoid issuer-dependent SVG loader rules in Turbopack and switch to query-based component imports or static public assets for CSS.