How to Fix: Turbopack loader ignores resource query on aliased imports
Turbopack currently drops the resource query when a module is imported through a configured alias, which means custom loader logic that depends on ?url, ?raw, or similar query suffixes never sees the expected signal. The result is confusing: the same import works when referenced directly, but fails or behaves differently once the path goes through alias resolution.
Problem Overview
In the reported reproduction, a loader is expected to react to a resource query appended to an import path. That pattern is common in bundler ecosystems where the same file can be processed in different ways depending on the query string. For example, an SVG may be imported as a URL in one place and transformed into a component elsewhere.
The bug appears specifically when the import path uses an aliased import. Instead of preserving the original request, Turbopack resolves the alias first and effectively loses the query metadata before the loader pipeline evaluates the request. Because the loader only receives the normalized file path and not the query component, it cannot branch correctly.
This is why you may observe behavior like:
- Direct relative imports with a query behaving correctly.
- Aliased imports resolving to the right file but skipping query-sensitive loader behavior.
- Different results between Webpack and Turbopack in the same codebase.
Understanding the Root Cause
The core issue is the interaction between module resolution and loader request parsing. In a healthy pipeline, an import such as @/icons/logo.svg?url should preserve two distinct pieces of information:
- The resolved resource path: the actual file on disk after alias expansion.
- The resource query:
?url, which downstream loaders can inspect.
With this bug, the alias is resolved, but the request metadata is not carried forward intact. Technically, that means the loader receives something equivalent to the file path alone, not the full request. If your loader condition depends on resourceQuery, it sees an empty or missing value and falls back to default behavior.
This usually affects setups where:
- A Next.js app runs with Turbopack enabled.
- A custom rule or loader branches based on resource query parameters.
- The import path uses tsconfig/jsconfig paths or another alias mapping.
In other words, this is not primarily a loader implementation mistake. It is a bundler request propagation issue triggered by aliased resolution.
Step-by-Step Solution
Until the underlying Turbopack behavior is fixed upstream, the safest workaround is to avoid query-dependent aliased imports in the affected code paths. Use one of the following approaches.
1. Replace aliased query imports with relative imports
If you have an import like this:
import logoUrl from '@/assets/logo.svg?url'
Change it to a direct relative import from the file location:
import logoUrl from '../assets/logo.svg?url'
This keeps the resource query attached to the request in a way that Turbopack currently handles more reliably.
2. Split query-sensitive assets into dedicated wrapper modules
If relative paths are too fragile, create a small module that imports the asset without relying on alias-plus-query combinations in consuming files.
// src/assets/logo-url.ts
import logoUrl from './logo.svg?url'
export default logoUrl
Then import the wrapper using your alias:
import logoUrl from '@/assets/logo-url'
This works because the alias now points to a normal module file, and the query stays inside a direct local import where the loader can still detect it.
3. Avoid resource-query branching when a static alternative exists
If your use case can be expressed with separate entry files instead of query suffixes, that is often more stable across bundlers.
// Instead of:
import icon from '@/icons/check.svg?component'
import iconUrl from '@/icons/check.svg?url'
// Prefer explicit modules:
import CheckIcon from '@/icons/check-icon'
import checkIconUrl from '@/icons/check-icon-url'
Example wrapper modules:
// src/icons/check-icon.tsx
export { default } from './check.svg'
// src/icons/check-icon-url.ts
import url from './check.svg?url'
export default url
This pattern reduces dependence on bundler-specific query handling.
4. Verify your alias configuration is not masking the bug
Check that your path alias is defined consistently across your project configuration.
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
And confirm your imports resolve to the same physical file whether you use the alias or the relative path. If relative imports work and aliased imports do not, that strongly confirms you are hitting this specific Turbopack issue rather than a general path configuration problem.
5. Temporarily fall back to Webpack for affected workflows
If your application heavily depends on query-aware loaders and refactoring is not practical, use the more stable bundler path until the bug is fixed upstream.
// Run without Turbopack if your project supports it
pnpm dev
If your current setup enables Turbopack by default, disable that behavior in the project-specific way you have configured it. The exact switch varies by project version, but the goal is simple: use the bundler path where aliased imports preserve resource queries.
6. Validate the fix locally
After applying one of the workarounds, test both forms of import behavior:
// Query-sensitive import should now behave correctly
import assetUrl from '../assets/file.svg?url'
// Normal import should still behave correctly
import AssetComponent from '../assets/file.svg'
Then restart the dev server and confirm that the loader output differs appropriately between the plain resource and the query-specific resource.
Common Edge Cases
- Mixed alias systems: If you use TypeScript path aliases, framework aliases, and package export maps together, it can become harder to identify which resolution layer is dropping the query.
- SVG dual-mode imports: Projects that import the same SVG both as a component and as a URL are especially likely to expose this bug.
- Loader assumptions: Some loaders expect
resourceQuery; others inspect the entire request string. If the loader is custom, verify exactly which field it reads. - Dev vs build mismatch: A setup may fail only in development if Turbopack is used there while another bundler handles production.
- Wrapper file location: If you create wrapper modules, keep the asset import inside a nearby file so the relative path remains obvious and maintainable.
FAQ
Why does the import work without the alias?
Because the bug is tied to the alias resolution path. Direct relative imports are more likely to preserve the original request, including the resource query, all the way to the loader.
Is this a problem in my loader configuration?
Usually no. If the same query-based import works with a relative path or under Webpack, your loader logic is probably fine. The issue is that Turbopack is not passing the query through correctly after alias resolution.
What is the best long-term fix?
The real fix needs to happen in Turbopack so aliased imports preserve full request metadata. Until that lands, the most maintainable workaround is to use wrapper modules or replace query-sensitive aliased imports with direct relative imports in the small number of places that need them.
For teams affected by this issue today, the practical rule is simple: do not rely on resource queries on aliased imports in Turbopack. Preserve query-based imports in direct file references, or wrap them behind explicit modules so your code stays stable while the upstream bug is addressed.