All skills
expo avatar

/expo-module

@5c8f62e official
by expoexpo/skills2.6k stars
156

Framework (OSS). Guide for creating and writing Expo native modules and views using the Expo Modules API (Swift, Kotlin, TypeScript). Covers module definition DSL, native views, shared objects, config plugins, lifecycle hooks, autolinking, and type system. Use when building or modifying native modules for Expo. Not for migrating an existing Swift module from the definition DSL to the Expo Modules API 2.0 macros; use expo-migrate-module (from the expo-experiments plugin) for that.

Use this Skill: https://skilld.dev/gh/expo/skills/expo-module

This session only. Nothing lands on disk.

referencescreate-expo-module.md

≈2.5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

create-expo-module

Use create-expo-module to scaffold new Expo modules and create-expo-module add-platform-support to extend existing Expo modules.

Prefer create-expo-module over manually creating module files and directories. In most cases, the right move is to generate the scaffold first and then build on top of it.

Choose the Module Type First

Local module

Use a local module when the native code only belongs to one Expo app.

  • lives inside the app
  • uses the app's dependencies and tooling
  • does not create an example app
  • respects package.json:expo.autolinking.nativeModulesDir, or falls back to modules/

Standalone module

Use a standalone module when the module should be reusable across apps, live in a monorepo package, or be published to npm.

  • has its own package.json
  • installs its own dependencies
  • builds TypeScript during scaffolding
  • usually creates an example app unless --no-example is passed
  • may initialize a Git repo if not already inside one

When creating a standalone module, default to keeping the example app. Only skip it when the user explicitly asks for --no-example or clearly does not want the example project.

Recommended Commands

Local module

Use an explicit slug or path.

npx create-expo-module@latest key-value-store --local --platform apple android --features Function AsyncFunction

If you need deterministic non-interactive output, pass the slug or path explicitly and then pass the rest of the options:

EXPO_NONINTERACTIVE=1 npx create-expo-module@latest key-value-store \
  --local \
  --name KeyValueStore \
  --package expo.modules.keyvaluestore \
  --platform apple android \
  --features Function AsyncFunction

Important quirk:

  • in non-interactive local scaffolding, omitting the positional slug causes the CLI to fall back to my-module
  • --name changes the native module class name, not the directory name

Standalone module

npx create-expo-module@latest expo-key-value-store --platform apple android --features Function AsyncFunction

Creation Options

These are the module creation options exposed by the CLI:

Option Applies to Notes
[path] local, standalone Positional slug or target path. Use this explicitly for stable local scaffolding in non-interactive mode.
--local local Create a local module inside the current Expo project.
--platform <platforms...> local, standalone Valid values: apple, android, web.
--features <features...> local, standalone Pick generated feature examples. Use all to include everything.
--full-example local, standalone Equivalent to --features all.
--barrel local Generate a local index.ts barrel. Ignored for standalone modules.
--source <source_dir> local, standalone Use a local expo-module-template directory instead of downloading from npm.
--name <name> local, standalone Native module name, for example KeyValueStore.
--description <description> standalone Package description.
--package <package> local, standalone Android package name, for example expo.modules.keyvaluestore.
--author-name <name> standalone Package author name.
--author-email <email> standalone Package author email.
--author-url <url> standalone Package author profile URL.
--repo <url> standalone Package repository URL.
--license <license> standalone Package license identifier.
--module-version <version> standalone Initial package version.
--package-manager <manager> standalone One of npm, pnpm, yarn, bun.
--with-readme standalone Keep README.md in the generated package.
--with-changelog standalone Keep CHANGELOG.md in the generated package.
--no-example standalone Skip creating the example app.

Notes:

  • --description, author flags, --repo, --license, and --module-version only affect standalone modules because local modules do not have a standalone package manifest.
  • --with-readme, --with-changelog, --no-example, and --package-manager are standalone-only concerns.
  • --barrel only affects local modules.
  • --name changes the native module class name. It does not rename the local module directory.

Platforms

Valid values are:

  • apple
  • android
  • web

Behavior to remember:

  • standalone modules default to all platforms when --platform is omitted in non-interactive mode
  • local modules also default to all platforms in non-interactive mode
  • interactive local scaffolding preselects platforms from app.json:expo.platforms when available, mapping ios to apple
  • invalid platform values are ignored with a warning; if all provided values are invalid, the CLI falls back to all platforms

If you do not want web support, omit web during scaffolding instead of removing it later.

Feature Examples

Feature examples are generated starter snippets, not capability restrictions. They are small working examples of common Expo Modules API patterns.

Available values:

  • Constant
  • Function
  • AsyncFunction
  • Event
  • View
  • ViewEvent
  • SharedObject

Important behaviors:

  • no features selected means a minimal module
  • in interactive mode, feature examples start unselected
  • in non-interactive mode, no features are included unless --features or --full-example is passed
  • --full-example is equivalent to --features all
  • ViewEvent automatically includes View

Use View only when the module actually renders UI. For native-only modules, do not scaffold the view files unless you plan to use them.

Local Module Quirks

  • local modules do not generate an index.ts barrel by default
  • use --barrel only if you want a root barrel file
  • local modules skip dependency installation and do not create an example app
  • local modules do not have a local package.json; they rely on the host app

If --barrel is not used, the CLI's follow-up instructions point to direct imports from the module's src/ files.

Standalone Module Quirks

  • --package-manager is only relevant for standalone modules
  • if omitted, the CLI detects the package manager from the user agent or available package managers
  • the scaffold builds TypeScript after installing dependencies
  • the example app is created only when examples are enabled; --no-example skips it
  • --with-readme and --with-changelog opt into those files

The generated standalone scripts include build, clean, test, prepare, open:ios, and open:android.

add-platform-support

Use this subcommand when an existing Expo module needs another supported platform.

Interactive usage from the module root:

npx create-expo-module@latest add-platform-support

Explicit usage:

npx create-expo-module@latest add-platform-support --platform android

You can also pass the module path:

npx create-expo-module@latest add-platform-support ./packages/expo-key-value-store --platform web

Important behaviors:

  • supported values are apple, android, and web
  • in non-interactive mode, --platform is required
  • the command only adds platforms that are not already present in expo-module.config.json
  • it refuses to overwrite existing android/ or ios/ directories
  • for native modules, it only works with modules that use the Expo Modules API DSL
  • older module formats are not supported

Feature detection

add-platform-support tries to detect the existing module's feature examples from the native module definition. This is best effort.

Use --features to override the detected feature examples when:

  • the module is unusual
  • the module uses generated code
  • the definition is spread across multiple files
  • the generated files do not match the existing module's shape

If no features are detected or provided, the command creates a minimal scaffold for the new platform.

Environment Variables

  • EXPO_BETA: use the next template version
  • EXPO_DEBUG: enable debug logs
  • EXPO_NO_TELEMETRY: disable telemetry
  • EXPO_NONINTERACTIVE: force non-interactive mode
  • CI: same as EXPO_NONINTERACTIVE, used in CI environments

Source: SKILL.md on GitHub

No alerts17d4 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    The skill provides developer documentation and reference guides for creating and writing Expo native modules and views. All code examples and scripts align with legitimate development practices, and no security risks were identified.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 5c8f62e. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 3 days ago.

Activeupdated 2 months ago
version
1.0.0
  • TypeScript
  • expo
  • native-modules
  • swift
  • kotlin
  • react-native
  • ios
  • android
  • config-plugins

README badge

README badge for expo/skills/expo-module

Guides you through creating and modifying Expo native modules in Swift (iOS) and Kotlin (Android), with TypeScript bindings. Use this skill when building native modules, native views, config plugins, or wrapping platform SDKs for React Native consumption.

Generated from the current SKILL.md.

What is the difference between a local module and a standalone module?
Local modules are for a single app and live in expo.autolinking.nativeModulesDir or modules/ folder, using the host app's tooling. Standalone modules have their own package metadata, scripts, and example app, and are intended for reuse, monorepos, or publishing.
Should I manually create native files or use create-expo-module?
Use create-expo-module to scaffold. It sets up the expected layout, expo-module.config.json, podspec/Gradle files, TypeScript bindings, and the example app flow. Manually creating files is error-prone and not recommended.
How do I add a new platform to an existing Expo module?
Use create-expo-module add-platform-support instead of manually copying native directories. This ensures correct file placement and configuration.
What platforms does this skill cover?
Swift (iOS), Kotlin (Android), and TypeScript. The skill provides DSL patterns for all three to create modules, native views, and shared objects.
Do I need to manually edit expo-module.config.json?
The scaffold generates it automatically, but you may need to edit it to register native modules and configure platform-specific settings like fully-qualified class names for Android.

Generated from the current SKILL.md. These answers refresh after source changes.