Skip to main content
The create-target CLI tool helps you quickly scaffold Apple targets (widgets, app clips, extensions, etc.) in your Expo project.

Usage

Interactive mode

Run without arguments to select from a list of available target types:
npx create-target
You’ll see an interactive prompt:
? Choose a target: (Use arrow keys)
 Widget - Home screen widget
  App Clip - Instantly open your app without installing
  Action - Headless action that appears in share sheets
  Share Extension
  Notification Content
  ...

Direct creation

Specify a target type directly to skip the interactive prompt:
npx create-target widget
npx create-target clip
npx create-target share

Options

--no-install
boolean
Skip installing @bacons/apple-targets package. Use this if the package is already installed.
--version
boolean
Display the CLI version number.Alias: -v
--help
boolean
Show usage information and available options.Alias: -h

Package manager detection

The CLI automatically detects which package manager you’re using based on how you invoke it:
Package ManagerCommand
npmnpx create-target
yarnyarn create target
pnpmpnpm create target
bunbun create target

What gets created

When you run create-target, the following happens:

1. Package installation

If @bacons/apple-targets is not already installed:
npx expo install @bacons/apple-targets

2. Config plugin setup

The plugin is automatically added to your app.json or app.config.js:
app.json
{
  "expo": {
    "plugins": [
      "@bacons/apple-targets"
    ]
  }
}

3. Target directory structure

A new directory is created at /targets/<target-name>/ with the following files:
targets/
└── widget/                    # or your chosen target type
    ├── expo-target.config.js  # Target configuration
    ├── Info.plist             # Target Info.plist
    └── *.swift                # Swift source files (varies by type)

Example: Widget target

npx create-target widget
Creates:
targets/widget/
├── expo-target.config.js
├── Info.plist
├── index.swift
├── widgets.swift
├── AppIntent.swift
├── WidgetControl.swift
└── WidgetLiveActivity.swift

Example: Share extension

npx create-target share
Creates:
targets/share/
├── expo-target.config.js
├── Info.plist
└── ShareViewController.swift

Example: App Clip

npx create-target clip
Creates:
targets/clip/
├── expo-target.config.js
├── Info.plist
├── AppDelegate.swift
└── Assets.xcassets/

Generated config file

Each target includes a pre-configured expo-target.config.js with sensible defaults:
targets/widget/expo-target.config.js
/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = config => ({
  type: "widget",
  icon: 'https://github.com/expo.png',
  entitlements: { /* Add entitlements */ },
});
For watch targets:
targets/watch/expo-target.config.js
/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = config => ({
  type: "watch",
  icon: 'https://github.com/expo.png',
  colors: { $accent: "darkcyan", },
  deploymentTarget: "9.4",
  entitlements: { /* Add entitlements */ },
});
For share extensions:
targets/share/expo-target.config.js
/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = config => ({
  type: "share",
  icon: 'https://github.com/expo.png',
  "frameworks": ["UIKit", "Social", "MobileCoreServices", "UniformTypeIdentifiers"],
  entitlements: { /* Add entitlements */ },
});

Interactive prompts

Target selection

When running without arguments, you’ll see a searchable list of all available target types:
? Choose a target:
  Widget - Home screen widget
  App Clip - Instantly open your app without installing  
  Action - Headless action that appears in share sheets
  Keyboard Extension - Custom system keyboard
  Content Blocker - Safari content blocker extension
  Share Extension
  Notification Content
  Notification Service
  Siri Intent
  # ... and 30+ more

Overwrite confirmation

If the target directory already exists and is not empty:
? Target directory targets/widget is not empty. Continue? (Y/n)
  • Yes: Removes existing files and creates fresh target
  • No: Exits without making changes
  • CI mode: Automatically fails (no interactive prompts)

Next steps

After creating a target:
Terminal output
Writing expo-target.config.js file
Writing Info.plist file
Target created! Run npx expo prebuild -p ios to fully generate the target. Develop native code in Xcode.
  1. Configure the target by editing /targets/<name>/expo-target.config.js
  2. Generate the Xcode project:
    npx expo prebuild -p ios --clean
    
  3. Open in Xcode:
    xed ios
    
  4. Develop your target inside the expo:targets/<name> folder in Xcode

Available target types

The CLI supports 40+ target types. Run npx create-target to see the full list, including:
  • widget - Home screen widgets with WidgetKit
  • clip - App Clips for instant experiences
  • share - Share extensions
  • action - Action extensions
  • notification-content - Custom notification UI
  • notification-service - Notification service extensions
  • intent / intent-ui - Siri shortcuts
  • safari - Safari extensions
  • keyboard - Custom keyboards
  • watch / watch-widget - Apple Watch apps
  • content-blocker - Safari content blockers
  • And many more network, authentication, and system extensions

Troubleshooting

Invalid target error

If you specify an invalid target:
npx create-target invalid-name
Output
Invalid target: invalid-name. Please choose one of: widget, clip, share, ...

Project not found

Error: Could not find Expo project root directory from: /path/to/dir.
Please run this command from the root directory of your Expo project,
or create one with: npx create-expo.
Solution: Run the command from your Expo project root (the directory containing package.json and app.json).

CI environment

Interactive prompts are disabled in CI environments. Always specify the target type:
# ✅ Works in CI
npx create-target widget

# ❌ Fails in CI (requires interaction)
npx create-target

Environment variables

EXPO_DEBUG
boolean
default:"false"
Enable debug logging to see detailed information about the creation process.
EXPO_DEBUG=1 npx create-target widget
CI
boolean
default:"false"
Automatically detected. When set, disables all interactive prompts.

Examples

Create a widget with debug output

EXPO_DEBUG=1 npx create-target widget

Create without installing dependencies

npx create-target widget --no-install

Create multiple targets

npx create-target widget
npx create-target share
npx create-target clip

Using with different package managers

npm
npx create-target widget
yarn
yarn create target widget
pnpm
pnpm create target widget
bun
bun create target widget

Build docs developers (and LLMs) love