Production-ready app icon badging for modern Expo and React Native workflows.
app-icon-badge-next is the production-ready successor to app-icon-badge, focused on reliability in CI/EAS, support for modern Expo icon models, and predictable results across current iOS and Android launcher behavior.
Mobile teams often install multiple builds of the same app (development, QA, staging, production). When icons look identical, QA and debugging slow down.
app-icon-badge-next overlays clear environment/version badges on icons so builds are easy to identify at a glance.
- Expo config plugin and library API support.
- Platform-aware badge configuration:
- shared
badges ios.badgesandroid.badges
- shared
- Android adaptive icon safe-zone support (
adaptiveSafeMode,android.safeZoneScale). - Badge text controls:
fontScale,padding,letterSpacing,opacity. - Deterministic cache support to skip unchanged generations.
- Debug and dry-run modes for safer CI usage.
- Expo 54+ icon model handling (root icon, Android icon + adaptive foreground, iOS string and object variants).
# yarn
yarn add app-icon-badge-next
# npm
npm install app-icon-badge-next
# pnpm
pnpm add app-icon-badge-next// app.config.ts
import type { ConfigContext, ExpoConfig } from '@expo/config';
import type { AppIconBadgeConfig } from 'app-icon-badge-next/types';
const VERSION = '1.0.1';
const APP_ENV = 'QA';
const appIconBadgeConfig: AppIconBadgeConfig = {
enabled: true,
cache: true,
debug: false,
dryRun: false,
adaptiveSafeMode: true,
badges: [
{
text: APP_ENV,
type: 'banner',
color: 'white',
background: '#FF0000',
fontScale: 1,
padding: 0,
letterSpacing: 0,
opacity: 1,
},
],
ios: {
badges: [
{ text: VERSION, type: 'ribbon', position: 'right' },
],
},
android: {
safeZoneScale: 0.72,
badges: [
{ text: VERSION, type: 'ribbon', position: 'right' },
],
},
};
export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
name: 'my-app',
icon: './assets/icon.png',
android: {
icon: './assets/icon-android.png',
adaptiveIcon: {
foregroundImage: './assets/adaptive-icon.png',
backgroundColor: '#FFFFFF',
},
},
plugins: [['app-icon-badge-next', appIconBadgeConfig]],
});Plugin option summary (defaults in parentheses):
enabled: enable or disable generation (true).badges: shared badge layers for all platforms.ios.badges: iOS-only badge layers (falls back tobadges).android.badges: Android-only badge layers (falls back tobadges).android.safeZoneScale: safe-zone scale for adaptive foreground, 0.4-1 (0.72).adaptiveSafeMode: apply safe-zone transform for adaptive icons (true).cache: deterministic cache for unchanged inputs (true).debug: structured debug logs (false).dryRun: skip file writes (false).
The plugin rewrites configured icon paths to fixed outputs under .expo/app-icon-badge and generates the badged images at that moment (synchronously, before Expo's own icon handling reads them). A deterministic cache keyed on source bytes + badge config makes repeat evaluations no-ops, and the plugin is idempotent when Expo re-applies it to an already rewritten config.
Source: https://github.com/AdzeB/app-icon-badge-next/blob/main/src/plugin/app.plugin.ts
import { addBadge } from 'app-icon-badge-next';
import path from 'node:path';
const icon = path.resolve(__dirname, './assets/icon.png');
await addBadge({
icon,
dstPath: './assets/icon.environment.png',
badges: [
{
text: 'staging',
type: 'banner',
color: 'white',
background: '#FF0000',
fontScale: 1,
padding: 0,
letterSpacing: 0,
opacity: 1,
},
{
text: '1.0.1',
type: 'ribbon',
position: 'right',
},
],
isAdaptiveIcon: false,
adaptiveSafeMode: true,
safeZoneScale: 0.72,
debug: false,
dryRun: false,
});All options except icon and badges are optional. Defaults: isAdaptiveIcon: false, adaptiveSafeMode: true, safeZoneScale: 0.72, debug: false, dryRun: false. Omitting dstPath writes next to the source as <name>.result.<ext>.
Run the CLI:
npx app-icon-badge-next --helpCommand help:
Usage: app-icon-badge-next [options] [command]
Generate app icons with badges
Options:
-V, --version output the version number
-h, --help display help for command
Commands:
add-badge [options] <iconPath>
help [command] display help for command
add-badge options:
Usage: app-icon-badge-next add-badge [options] <iconPath>
Options:
--text <text> badge text
--type <type> badge type: banner | ribbon
--position <position> banner: top | bottom, ribbon: left | right
--background <background> badge background as #rrggbb
--color <color> badge text color: white | black (default: "white")
--platform <platform> target platform: ios | android | all (default: "all")
--preview write result to preview path (default: false)
--safe-zone enable adaptive safe zone (default: false)
--scale <scale> safe zone scale (0.4-1) (default: "0.72")
--dry-run no file write (default: false)
--debug debug logs (default: false)
-h, --help display help for command
Example:
npx app-icon-badge-next add-badge ./assets/icon.png \
--type banner \
--text QA \
--position top \
--background '#45f4ee' \
--color black \
--platform all \
--safe-zone \
--scale 0.72Contributions are welcome! See the contributing guide for setup, workflow, and release details.
pnpm install # install dependencies
pnpm type-check # TypeScript type checking
pnpm build # build dist/
pnpm test # run tests (requires a prior build)- Found a bug or want a feature? Open an issue.
- Security issue? Report it privately — see the security policy.
- This project follows the Contributor Covenant Code of Conduct.
Releases are automated with Changesets; see CHANGELOG.md for release notes.
Special thanks to the original project and maintainers:
- Original library: https://github.com/obytes/app-icon-badge
- Notable upstream fixes and context that influenced this successor:
License agreement and attribution:
app-icon-badge-nextis MIT licensed.- The original
obytes/app-icon-badgeproject is MIT licensed. - This successor preserves attribution to the original work and follows MIT license terms for reuse and distribution.
MIT. See LICENSE.