CLI Tools
rn-iconify includes command-line tools for analyzing icon usage and generating offline bundles.
Available Commandsโ
npx rn-iconify <command> [options]
| Command | Description |
|---|---|
bundle | Generate offline icon bundle |
analyze | Analyze icon usage in your project |
doctor | Report icons that would be fetched at runtime |
help | Show help message |
version | Show version |
Bundle Commandโ
Generate bundled icon files for offline use:
npx rn-iconify bundle --auto --output ./assets/icons.bundle.json
Optionsโ
| Option | Description | Default |
|---|---|---|
--src <path> | Source directory to analyze | ./src |
--output <path> | Output file path | ./assets/icons.bundle.json |
--auto | Auto-detect icons from source code | true |
--icons <list> | Comma-separated list of icons to include | - |
--exclude <list> | Comma-separated patterns to exclude | - |
--verbose | Show detailed output | false |
--pretty | Pretty-print JSON output | false |
Examplesโ
# Auto-detect and bundle icons from source
npx rn-iconify bundle --auto
# Bundle specific icons
npx rn-iconify bundle --icons "mdi:home,mdi:cog,heroicons:user"
# Custom output path
npx rn-iconify bundle --output ./src/generated/icons.bundle.json
# Verbose output
npx rn-iconify bundle --auto --verbose --pretty
Generated Bundleโ
The bundle command creates a JSON file with icon data:
{
"version": "2.0.0",
"generatedAt": "2025-12-03T10:30:00Z",
"icons": {
"mdi:home": {
"svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z\"/></svg>",
"width": 24,
"height": 24
}
},
"count": 47
}
Analyze Commandโ
Analyze icon usage across your project:
npx rn-iconify analyze
Outputโ
๐ Icon Usage Analysis
Found 47 unique icons across 23 files
By Icon Set:
mdi: 28 icons
heroicons: 12 icons
lucide: 7 icons
Most Used Icons:
1. mdi:home (12 usages)
2. mdi:arrow-left (8 usages)
3. heroicons:user (6 usages)
Recommendation:
npx rn-iconify bundle --icons "mdi:home,mdi:arrow-left,heroicons:user"
Optionsโ
| Option | Description | Default |
|---|---|---|
--src <path> | Source directory to analyze | ./src |
--format <type> | Output format: table, json, markdown | table |
--detailed | Show file locations for each icon | false |
--verbose | Show detailed output | false |
Examplesโ
# Analyze specific directory
npx rn-iconify analyze --src ./app
# JSON output for CI integration
npx rn-iconify analyze --format json > icon-usage.json
# Detailed view with file locations
npx rn-iconify analyze --detailed
# Markdown output for documentation
npx rn-iconify analyze --format markdown > ICONS.md
Doctor Commandโ
Report what your build ships and what it will ask the network for:
npx rn-iconify doctor
๐ฉบ rn-iconify doctor
Resolved from source : 105
Fetched at runtime : 71
Coverage : 60%
An icon the build cannot see is not a broken icon. IconRenderer fetches it
from the Iconify API instead, in release builds as much as in development โ a
request on every install, a placeholder until it lands, and nothing at all on a
device with no connection. None of that is visible from inside the app, which
is what this command is for.
Optionsโ
| Option | Description | Default |
|---|---|---|
--src <path> | Project root to inspect | cwd |
--strict | Exit non-zero if any icon is fetched at runtime | false |
--prune | Drop names not rendered lately from usage.json | false |
--stale-days <n> | How long a name may go unrendered before --prune drops it | 30 |
--format <type> | text or json | text |
--verbose | Show detailed output | false |
Not strict by default: a project part-way through fixing this should be able to see the number without being blocked by it.
Clearing out names that are goneโ
usage.json is written by the development server as your app renders icons the
build could not find, and it is why those icons still ship. That also means
nothing in it can be checked against your source โ it is exactly the set of
names your source does not mention.
npx rn-iconify doctor --prune
It clears two things.
Names the build now finds on its own. This file carries what the scan cannot prove, so a name it can prove is carried for no reason โ and after the scan learns a new shape, that is usually most of the file. Removing one cannot change what ships, so nothing is weighed and nothing is waited for.
Names nobody has rendered lately. The only evidence a name is gone is that it has not been rendered since the screen was deleted, which is why each one carries the time it was last seen.
[rn-iconify] Removed 149 name(s) the build now finds in your source.
Nothing changes: they were already being bundled from the code itself.
[rn-iconify] Removed 3 name(s) not rendered in 30 day(s):
ยท ion:airplane-outline โ last seen 2026-05-02T09:14:22.101Z
ยท ion:cafe-outline โ last seen 2026-05-02T09:14:31.660Z
ยท ion:trail-sign-outline โ last seen 2026-04-28T17:02:08.934Z
Nothing is removed without being named, and nothing is lost by being wrong: if one of them was still in use, open that screen once in development and it comes back.
This is a command rather than something the dev server does on its own. A screen opened twice a year is still a screen, and dropping its icons quietly would put them back on the network for the one person who opens it.
Upgrading a file written before names carried their own timestamps removes nothing. When each was last rendered was never recorded, so they are all stamped as seen at the upgrade โ the clock starts there and tells the truth from there on.
In CIโ
- name: Check icon coverage
run: npx rn-iconify doctor --strict
Fixing what it reportsโ
Most of what appears there is a name the source cannot tie to an icon set:
// Nothing says 'hanger' is an Mdi icon
const CATEGORY_ICON: Record<string, string> = { OUTFIT: 'hanger' };
Typing it is usually all it takes. The build follows an icon set type wherever you use it, so each of these is found without anything else:
// A record whose values are icons
const CATEGORY_ICON: Record<string, MdiIconName> = { OUTFIT: 'hanger' };
// A field, and the table that fills it
interface TabConfig { icon: IonIconName; route: string }
const TABS: TabConfig[] = [{ icon: 'home', route: 'Home' }];
// The type written out rather than imported
type IoniconName = ComponentProps<typeof Ion>['name'];
// An icon that depends on state โ both names are read
<Ion name={paused ? 'play' : 'pause'} />
Names handed to your own components need nothing either โ the prop type is enough.
defineIcons is for what is left:
a name assembled at runtime, or one that genuinely cannot carry a type.
const CATEGORY_ICON = defineIcons<MdiIconName>({ OUTFIT: 'hanger' });
.rn-iconify/usage.json collects icons the app fetched during development
and is read by the next build, which is why a project can look healthy while
depending on it. Doctor deliberately does not count those as resolved.
Integration with package.jsonโ
Add scripts for common operations:
{
"scripts": {
"icons:analyze": "rn-iconify analyze --src ./src",
"icons:bundle": "rn-iconify bundle --auto --output ./assets/icons.bundle.json",
"icons:bundle:verbose": "rn-iconify bundle --auto --verbose --pretty"
}
}
CI/CD Integrationโ
GitHub Actionsโ
# .github/workflows/icons.yml
name: Icon Analysis
on: [push, pull_request]
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm install
- name: Analyze Icons
run: npx rn-iconify analyze --format json > icon-report.json
- name: Upload Report
uses: actions/upload-artifact@v4
with:
name: icon-report
path: icon-report.json
Pre-commit Hookโ
Add icon analysis to pre-commit:
# .husky/pre-commit
npx rn-iconify analyze --src ./src
Loading Generated Bundleโ
Use the generated bundle in your app:
import { loadOfflineBundle } from 'rn-iconify';
import iconBundle from './assets/icons.bundle.json';
// Load at app startup
loadOfflineBundle(iconBundle);
// Icons are now available offline
<Mdi name="home" /> // Renders instantly
Troubleshootingโ
Command Not Foundโ
Ensure rn-iconify is installed:
npm install rn-iconify
Network Errorsโ
The CLI fetches icon data from Iconify API. If you have network issues:
# Check connectivity
curl https://api.iconify.design/mdi.json?icons=home
Permission Errorsโ
If output directory is protected:
# Check directory permissions
ls -la ./assets
# Or use a different directory
npx rn-iconify bundle --output ./generated/icons.bundle.json
Next Stepsโ
- Babel Plugin - Build-time bundling
- Offline Bundles - Full offline support
- Architecture - How it all works