expo-migrate-module

Migrates Swift Expo native modules from the 1.0 definition DSL to the 2.0 macro API.

Updated Sep 13, 2026
One-click install
npx skills add https://github.com/aadilmallick/myfitness-pal-clone --skill expo-migrate-module-aadilmallick
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: expo-migrate-module
Source: https://github.com/aadilmallick/myfitness-pal-clone/tree/main/.agents/skills/expo-migrate-module
Command: npx skills add https://github.com/aadilmallick/myfitness-pal-clone --skill expo-migrate-module-aadilmallick

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill includes references (resource) components.

What problem does it solve? Migrating an existing Expo native module from the Expo Modules API 1.0 definition DSL to the 2.0 macro API is risky: macro support varies across expo-modules-core versions, async threading semantics changed architecturally, and a careless rewrite can silently break the JavaScript contract. This Skill provides a verified, incremental migration workflow that preserves the module's observable JS/TypeScript API. ## Core Features & Use Cases - Contract-first migration: Inventories every exported member (functions, properties, events, records, shared objects, lifecycle hooks) and treats the existing JS/TS surface as the compatibility contract. - Compatibility verification: Checks the checked-out expo-modules-core for actual macro and runtime support before migrating each capability, instead of trusting SDK version numbers. - Mixed-mode fallback: Keeps unsupported or blocked members (views, static shared-object members, queue-pinned functions) in the 1.0 DSL alongside the migrated @ExpoModule, with guidance on tracking issues for gaps. - Use Case: You maintain an Expo module with AsyncFunction, Events, and Record definitions on SDK 57 and want to adopt @ExpoModule, @JS, @Event, and @Record macros without changing any JS call sites or moving blocking work onto the JS thread. ## Quick Start Ask the agent to migrate this Expo module's Swift implementation from the 1.0 definition DSL to the 2.0 macro API while preserving its JavaScript contract.

Frequently Asked Questions about expo-migrate-module

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I migrate an Expo module from the 1.0 DSL to the 2.0 macro API?

Inventory every exported member as the JS contract, verify macro and core support in the checked-out expo-modules-core, then migrate one semantic group at a time: naming, functions, properties, events, shared objects, records. Keep unsupported members in the 1.0 definition() block as mixed mode.

What Expo SDK version is required for the 2.0 macro API?

Use expo 57.0.21 or newer; earlier 57.x versions compile the macros but lack many 2.0 features. The macros are experimental in SDK 57 with the official beta in SDK 58, so verify the checked-out expo-modules-core rather than trusting version numbers.

Does the 2.0 macro API support Expo native views?

No, views are not covered by 2.0 yet. Keep UIKit View, Prop, view Events, and OnViewDidUpdateProps entries on the 1.0 DSL; a module with views migrates its non-view members and keeps the view in mixed mode.

Why does a migrated async function block the JS thread?

A 1.0 AsyncFunction ran off the JS thread, but a 2.0 async @JS member starts on the JS thread and leaves only at the first await. A body that never awaits blocks the JS thread; fix it with @JS(.concurrent) or restructure onto Swift Concurrency.

Can I migrate StaticFunction entries to @JS static members?

Only if the checked-out core declares the constructor:-labeled shared-object decoration hook; the prototype: overload shipped earlier, so static members can expand and then fail to link. Otherwise keep StaticFunction and StaticAsyncFunction entries in the 1.0 Class block.

When should I not use this migration approach?

Do not use it for creating a new module, general Expo SDK upgrades, or Android/Kotlin migrations, which stay on the 1.0 DSL. Also avoid it when the installed core lacks required runtime hooks and mixed mode cannot preserve the JS contract.