How to Import SVG Files in React Native (All Methods Explained)

Importing an SVG in React Native is not as simple as dropping it into an <Image> component. React Native's core Image documentation does not list SVG among its supported formats, and a raw .svg file is not a React component until something transforms it.
That leaves developers with several valid approaches: draw the SVG with components, convert it ahead of time, transform the file during bundling, parse an XML string, or load it from a URL. The right method depends on where the SVG comes from and whether you need to style or animate its individual elements.
In this guide, we will implement each practical method, explain its trade-offs, and fix the setup problems that usually make an SVG disappear.
- Use
react-native-svg components when the graphic needs dynamic colors, animation, or interaction.- Use SVGR when you want committed, type-safe icon components without changing Metro.
- Use
react-native-svg-transformer when you want import Logo from './logo.svg' across a local asset library.- Use
SvgXml when your API returns SVG markup as a string.Use SvgUri when a trusted server or CDN hosts the SVG.- Use
expo-image when you only need to display and cache an SVG as an image.- Do not use React Native's core
<Image> as a cross-platform SVG solution.Why React Native Needs an SVG Library
React Native does not render browser DOM elements such as <svg> and <path>. The react-native-svg package provides React Native components that map SVG elements to native drawing implementations on Android and iOS.
Install it before using the component, XML, URI, or transformer methods below.
For an Expo project:
npx expo install react-native-svgFor a bare React Native project:
npm install react-native-svg
cd ios && pod install && cd ..Do not run react-native link. React Native has used autolinking for native dependencies since version 0.60.
Now that the renderer is installed, let us choose how the SVG should enter the application.
Which SVG Method Should You Choose?
| Requirement | Recommended method | Main trade-off |
| Dynamic icon or chart | Inline react-native-svg component | SVG markup becomes application code |
| Local design-system icons | SVGR-generated components | Generated files must be refreshed when SVGs change |
Direct local .svg imports | Metro transformer | Requires bundler and test configuration |
| SVG markup returned by an API | SvgXml | Parses the XML at runtime |
| SVG hosted on a CDN | SvgUri | Depends on the network and remote asset availability |
| Cached, display-only SVG in Expo | expo-image | Cannot target individual paths for styling or animation |
Method 1: Build an SVG with react-native-svg Components
This is the most direct approach. It works well for icons, progress rings, charts, and illustrations whose colors or shapes change with application state.
import Svg, { Circle, Path, type SvgProps } from 'react-native-svg';
type CheckBadgeProps = SvgProps & {
iconColor?: string;
};
export function CheckBadge({
iconColor = '#2563EB',
...props
}: CheckBadgeProps) {
return (
<Svg width={48} height={48} viewBox="0 0 48 48" {...props}>
<Circle cx={24} cy={24} r={22} fill="#E0E7FF" />
<Path
d="M14 24l7 7 13-15"
fill="none"
stroke={iconColor}
strokeWidth={4}
strokeLinecap="round"
strokeLinejoin="round"
/>
</Svg>
);
}Because the path is part of the component tree, you can pass props, respond to state, or animate specific properties. The viewBox is important: it defines the internal coordinate system and lets the graphic scale without rewriting every path.
The drawback appears with large illustrations. Hundreds of lines of generated paths are difficult to review and maintain by hand. For those assets, conversion or file-based imports are cleaner.
Method 2: Convert SVG Files into React Native Components with SVGR
SVGR converts SVG markup into a React component that uses react-native-svg. This gives you a normal .tsx file without adding custom behavior to Metro.
Install the CLI as a development dependency:
npm install --save-dev @svgr/cliBefore converting files, add svgr.config.js. This tested configuration produces React Native TypeScript, removes fixed root dimensions, preserves viewBox, and removes the XML namespace attribute that React Native does not need and SvgProps may reject during type-checking:
module.exports = {
native: true,
typescript: true,
dimensions: false,
svgoConfig: {
plugins: [
{
name: 'preset-default',
params: {
overrides: {
removeViewBox: false,
},
},
},
{
name: 'removeAttrs',
params: {
attrs: 'svg:xmlns',
},
},
],
},
};Now convert one file:
npx svgr assets/logo.svg --out-dir src/iconsOr convert an entire icon directory:
npx svgr assets/icons --out-dir src/iconsThen import the generated component normally:
import Logo from './icons/Logo';
export function Header() {
return <Logo width={120} height={40} />;
}SVGR's native option changes SVG elements into React Native-compatible components and removes unsupported nodes. Keep the original SVGs as the source of truth and regenerate the components when the design changes; manually editing generated path data creates drift.
That handles build-time conversion outside Metro. If your team wants to import the original files directly, use a transformer instead.
Let’s Build Your React Native App Together!
We build powerful React Native apps that run smoothly on iOS and Android — fast, reliable, and ready to scale.
Method 3: Import .svg Files Directly with a Metro Transformer
react-native-svg-transformer lets Metro convert an SVG into a component during bundling:
import Logo from './assets/logo.svg';
export function Header() {
return <Logo width={120} height={40} />;
}First install the transformer. react-native-svg must already be installed.
npm install --save-dev react-native-svg-transformerMetro Configuration for Expo
Create or update metro.config.js at the project root:
const { getDefaultConfig } = require('expo/metro-config');
module.exports = (() => {
const config = getDefaultConfig(__dirname);
const { transformer, resolver } = config;
config.transformer = {
...transformer,
babelTransformerPath: require.resolve(
'react-native-svg-transformer/expo'
),
};
config.resolver = {
...resolver,
assetExts: resolver.assetExts.filter((ext) => ext !== 'svg'),
sourceExts: [...resolver.sourceExts, 'svg'],
};
return config;
})();Metro Configuration for Bare React Native 0.72.1 and Newer
const {
getDefaultConfig,
mergeConfig,
} = require('@react-native/metro-config');
const defaultConfig = getDefaultConfig(__dirname);
const { assetExts, sourceExts } = defaultConfig.resolver;
const config = {
transformer: {
babelTransformerPath: require.resolve(
'react-native-svg-transformer/react-native'
),
},
resolver: {
assetExts: assetExts.filter((ext) => ext !== 'svg'),
sourceExts: [...sourceExts, 'svg'],
},
};
module.exports = mergeConfig(defaultConfig, config);Preserve any existing Metro options when merging this setup. Replacing the entire configuration can break other transformers, monorepo paths, or Expo defaults.
TypeScript Declaration for SVG Imports
Metro can bundle the file, but TypeScript still needs to know what the import represents. Add declarations.d.ts:
declare module '*.svg' {
import type React from 'react';
import type { SvgProps } from 'react-native-svg';
const content: React.FC<SvgProps>;
export default content;
}Make sure the declaration file is included by tsconfig.json. Restart Metro with a clean cache after changing its configuration:
npx react-native start --reset-cacheFor Expo, use:
npx expo start --clearDirect imports are convenient, but remember what the configuration does: .svg moves from Metro's asset extensions to its source extensions. It is now treated as component source, not as a normal image file.
Method 4: Render an SVG XML String with SvgXml
Sometimes an API, CMS, or database returns the SVG markup itself. SvgXml parses that string at runtime, so no local file import or Metro transformer is required.
import { SvgXml } from 'react-native-svg';
const badgeXml = `
<svg width="24" height="24" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10" fill="#2563EB" />
<path
d="M7 12.5l3 3 7-7"
fill="none"
stroke="#FFFFFF"
stroke-width="2"
/>
</svg>
`;
export function Badge() {
return <SvgXml xml={badgeXml} width={48} height={48} />;
}This method is flexible, but parsing happens at runtime. Avoid reparsing a large XML string during frequent renders, and only accept SVG content from sources you control or validate. A malformed or excessively complex document can still create rendering and performance problems.
Now let us handle the case where the server returns a URL rather than the XML itself.
Method 5: Load a Remote SVG with SvgUri
SvgUri fetches an SVG document and renders it through react-native-svg:
import { useState } from 'react';
import { Text } from 'react-native';
import { SvgUri } from 'react-native-svg';
export function RemoteLogo() {
const [failed, setFailed] = useState(false);
if (failed) {
return <Text>Logo unavailable</Text>;
}
return (
<SvgUri
uri="https://cdn.example.com/brand/logo.svg"
width={120}
height={40}
onError={() => setFailed(true)}
/>
);
}Always provide loading and failure behavior in production. If the remote document uses CSS inside a <style> element, the library also exposes SvgCssUri from react-native-svg/css; the official usage guide documents that variant.
Use HTTPS, restrict remote SVGs to trusted hosts, and consider fetching authenticated content yourself before passing the verified string to SvgXml. SvgUri is convenient, but it does not give you an image pipeline's full caching controls.
Method 6: Display an SVG with expo-image
If an Expo app only needs to display an SVG, expo-image supports the format on Android, iOS, and web and adds memory and disk caching.
npx expo install expo-imageimport { Image } from 'expo-image';
export function CachedRemoteLogo() {
return (
<Image
source="https://cdn.example.com/brand/logo.svg"
style={{ width: 120, height: 40 }}
contentFit="contain"
/>
);
}Choose this method for display and caching, not SVG-level control. You cannot target a particular <Path> or animate its stroke as you can with react-native-svg. Expo also documents an iOS decoder limitation for some compact elliptical arc commands, so test optimized artwork on both platforms.
There is one more configuration caveat: when react-native-svg-transformer treats local .svg files as source modules, the same imports are no longer ordinary image assets. Pick one local-file strategy consistently or create an explicitly tested asset convention.
How to Change SVG Colors
Passing fill to an imported component does not automatically override hardcoded colors on every child path. This SVG will remain black even if the root receives fill="red":
<path fill="#000000" d="..." />For inline or generated components, replace the hardcoded value with a prop:
<Path fill={color} d="..." />For transformer-based imports, use an SVGR configuration to replace known design colors with currentColor or a component prop. Do not blindly replace every fill: multi-color illustrations often need their original palette.
Can You Animate SVGs in React Native?
Yes. Since react-native-svg exposes elements as components, you can animate their props with React Native's Animated API or a compatible animation library such as Reanimated. Keep the SVG simple, animate only the properties that need to change, and profile continuous animations on lower-end Android devices.
If an animation is already delivered as Lottie, Rive, or video, converting it into a large SVG path animation may add complexity without improving the result. Choose the format based on the animation pipeline, not only on visual sharpness.
Let’s Build Your React Native App Together!
We build powerful React Native apps that run smoothly on iOS and Android — fast, reliable, and ready to scale.
Common React Native SVG Problems
Unable to resolve module ./logo.svg
Metro is still treating .svg as an unsupported import. Confirm that svg was removed from assetExts, added to sourceExts, and that the correct /expo or /react-native transformer entry is configured. Then clear Metro's cache.
TypeScript says it cannot find the SVG module
Add the *.svg declaration shown earlier and ensure tsconfig.json includes the declaration file. This is a type-system problem, not a Metro problem.
The SVG renders at the wrong size or gets clipped
Preserve a correct viewBox and give the rendered component explicit dimensions. Removing viewBox during optimization is a common cause of scaling problems, particularly on Android.
The color prop does nothing
Inspect the source for hardcoded fill and stroke values. Root props cannot override a value explicitly set on a child path.
The SVG works in a browser but not in React Native
Browser SVG implementations support more of the SVG and CSS specifications. External stylesheets, custom fonts, filters, masks, and complex CSS may need to be simplified or converted to paths. Test the actual Android and iOS renderers rather than treating browser output as proof.
Jest fails when a component imports an SVG
Metro's transformer is not automatically used by Jest. Map .svg imports to a mock in the Jest configuration, or transform them with a test-specific setup. The transformer project's README includes a current moduleNameMapper example.
SVG or PNG: Which Should You Use?
SVG is usually the better fit for logos, icons, diagrams, and simple illustrations that must scale or change color. PNG is often better for screenshots, textured artwork, and other pixel-based images. Photographs belong in formats such as JPEG, WebP, or AVIF rather than SVG.
SVG is not automatically smaller. A highly detailed vector with thousands of points can outweigh an optimized raster asset and cost more to render. Compare real file sizes and profile the screen instead of choosing by extension alone.
Frequently Asked Questions
Can React Native's <Image> component display SVG files?
React Native's core Image documentation does not include SVG in its supported format list. Use react-native-svg, a transformer, or a supported image library such as expo-image instead of depending on platform-specific behavior.
Does Expo support SVG files?
Yes. Install react-native-svg with npx expo install react-native-svg for SVG components, XML, and URI rendering. Direct .svg component imports still require Metro configuration. expo-image is another option when you only need image-style display and caching.
Do I need both react-native-svg and react-native-svg-transformer?
Only for direct imports such as import Logo from './logo.svg'. The transformer converts the file during bundling; react-native-svg provides the components used to render the result.
Can I load an SVG from an API?
Use SvgXml when the API returns SVG markup and SvgUri when it returns a URL. Validate the source, handle loading and errors, and avoid repeatedly parsing large documents.
Why does my imported SVG ignore fill?
One or more child elements probably contain a hardcoded fill or stroke. Remove those fixed values, expose color props in a generated component, or configure SVGR to replace selected colors.
Are SVGs always better than PNGs?
No. SVGs are ideal for scalable vector artwork. PNG remains appropriate for pixel-based graphics, and a very complex SVG can be larger or slower than an optimized raster image.
Conclusion
There is no single best SVG import method for every React Native screen. Local reusable icons work well as components, transformer imports keep asset usage concise, XML and URI renderers handle dynamic content, and expo-image is useful when caching matters more than path-level control.
The important part is to choose the method before the asset library grows. A consistent pipeline makes colors, testing, caching, and bundle behavior predictable, and prevents every developer from solving the same SVG problem differently.



