Skip to main content
Expo Modules is a native module system that makes it easy to write native code that works seamlessly across iOS and Android. It powers all Expo SDK modules and is available for your custom native code.

What are Expo Modules?

Expo Modules provide a modern, type-safe API for writing native modules. Instead of writing separate bridging code for React Native’s legacy bridge, you write native code once using the Expo Modules API.

Type Safety

TypeScript types are automatically generated from native code definitions

Cross-Platform

Write native APIs once, works on both iOS and Android

Auto-linking

Modules are automatically discovered and linked into your app

Modern APIs

Uses Swift for iOS and Kotlin for Android, leveraging modern language features

Architecture

expo-modules-core

The expo-modules-core package is the foundation of the Expo Modules system. It provides:
  • Native Module API: High-level APIs for defining modules in Swift/Kotlin
  • Autolinking: Automatic discovery and registration of modules
  • Type Generation: Automatic TypeScript type definitions
  • JSI Integration: Direct JavaScript ↔ Native communication (no bridge)
Key Components:

Module Structure

Every Expo module has this structure:

Creating an Expo Module

Quick Start

Use the official tool to scaffold a new module:
This creates a complete module with:
  • iOS and Android native implementations
  • TypeScript definitions
  • Example app for testing
  • Autolinking configuration

Module Configuration

The expo-module.config.json defines module metadata:
expo-module.config.json

Writing Native Code

iOS (Swift)

Expo modules use a declarative Swift DSL:
ios/ExampleModule.swift
Key Swift APIs:
  • Name() - Module name exposed to JavaScript
  • Function() - Synchronous function
  • AsyncFunction() - Async function (returns Promise)
  • Property() - Getter/setter for module property
  • Events() - Event emitter names
  • View() - Native UI component
  • Prop() - Component prop definition

Android (Kotlin)

Android modules use a similar Kotlin DSL:
android/src/main/java/expo/modules/example/ExampleModule.kt

JavaScript Interface

The JavaScript side defines the public API:
src/ExampleModule.ts

React Components

Create native UI components:

iOS View

ios/ExampleView.swift

Android View

android/src/main/java/expo/modules/example/ExampleView.kt

React Component

src/ExampleView.tsx

Autolinking

Expo modules are automatically linked using expo-modules-autolinking.

How Autolinking Works

1

Module installed

Install module: npx expo install expo-example-module
2

Build triggered

Run npx expo prebuild or build command
3

Autolinking scans

Scans node_modules for packages with expo-module.config.json
4

Native config generated

Generates iOS Podfile and Android Gradle config
5

Module registered

Module is automatically registered in the app

iOS Autolinking

In your Podfile:
ios/Podfile

Android Autolinking

In your settings.gradle:
android/settings.gradle
In your app/build.gradle:
android/app/build.gradle

Real-World Examples

expo-battery

A simple module that reads battery level: iOS:
JavaScript:

expo-camera

A complex module with native views and permissions: Module Definition:

Type Safety

Expo Modules automatically generate TypeScript types:
src/ExampleModule.types.ts

Testing Modules

The create-expo-module tool includes an example app:
Test your module in the example app before publishing.

Best Practices

Prefer AsyncFunction over Function for operations that might take time. This prevents blocking the JavaScript thread.
Use proper error handling and throw descriptive errors:
Specify all types explicitly for better auto-generated TypeScript types:
Implement proper cleanup for views and listeners:

Common Patterns

Permissions

Events

Native Views

Next Steps

Architecture

Understand how all pieces fit together

Development Workflow

Learn the development cycle

Create a Module

Build your first Expo module

Tutorial

Build a complete app