A config plugin is a JavaScript function that receives the app config and returns it, possibly with mods attached: callbacks that prebuild runs against one native file each. Expo 6,418 provides typed mods for common files (withAndroidManifest, withGradleProperties, withMainApplication and more) and withDangerousMod for raw file access. BookNest needs three changes to survive prebuild --clean: the x86_64-only build that Android Permissions promised, the Turbo Native Module's Kotlin files, which live in native/android/share/, and the line that registers their package:
// 1. Build native code for the emulator's ABI only (Section 3.14.8)
const withX86Only = (config) =>
withGradleProperties(config, (c) => {
c.modResults = c.modResults.filter((p) => p.key !== 'reactNativeArchitectures');
c.modResults.push({ type: 'property', key: 'reactNativeArchitectures', value: 'x86_64' });
return c;
});
// 2. Copy the Turbo Native Module's Kotlin sources into android/app
const withShareSources = (config) =>
withDangerousMod(config, ['android', async (c) => {
const from = path.join(c.modRequest.projectRoot, 'native/android/share');
const to = path.join(c.modRequest.platformProjectRoot, 'app/src/main/java',
...PKG.split('.'));
fs.mkdirSync(to, { recursive: true });
for (const f of fs.readdirSync(from)) {
fs.copyFileSync(path.join(from, f), path.join(to, f));
}
return c;
}]);
// 3. Register its package in MainApplication.kt
const withSharePackage = (config) =>
withMainApplication(config, (c) => {
let src = c.modResults.contents;
if (!src.includes('BookSharePackage')) {
src = src.replace('import com.facebook.react.PackageList',
`import com.facebook.react.PackageList\nimport ${PKG}.BookSharePackage`);
src = src.replace('// add(MyReactNativePackage())', 'add(BookSharePackage())');
}
c.modResults.contents = src;
return c;
});
module.exports = (config) => withSharePackage(withShareSources(withX86Only(config)));List it in app.json as "./plugins/withBookNestAndroid". Typed mods hand you parsed content (modResults is an array of properties for gradle.properties) and write it back for you. The MainApplication.kt mod is string surgery on Expo's template, so make it idempotent (the includes check lets it run twice safely) and expect to revisit it when the template changes: Expo's docs warn that such regex-style mods are fragile and recommend Expo Modules where possible, which is why the Expo Module of Expo Modules in Kotlin needs no plugin at all.