Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions .github/workflows/cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ jobs:
${{ runner.os }}-yarn-

- name: 🧶 Install node modules in root dir
run: yarn install --prefer-offline --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --prefer-offline --frozen-lockfile --ignore-engines
env:
YARN_IGNORE_SCRIPTS: 'true'

Expand Down Expand Up @@ -162,7 +163,8 @@ jobs:

- name: 🧶 Install node modules in root dir
# NOTE(cedric): yarn v1 on Windows has networking issues, we need to set `--network-timeout` to a higher value
run: yarn install --prefer-offline --frozen-lockfile --network-timeout 1000000
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --prefer-offline --frozen-lockfile --network-timeout 1000000 --ignore-engines
env:
YARN_IGNORE_SCRIPTS: 'true'

Expand Down Expand Up @@ -213,7 +215,8 @@ jobs:
${{ runner.os }}-yarn-

- name: 🧶 Install node modules in root dir
run: yarn install --prefer-offline --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --prefer-offline --frozen-lockfile --ignore-engines
env:
YARN_IGNORE_SCRIPTS: 'true'

Expand Down Expand Up @@ -309,7 +312,8 @@ jobs:

- name: 🧶 Install node modules in root dir
# NOTE(cedric): yarn v1 on Windows has networking issues, we need to set `--network-timeout` to a higher value
run: yarn install --prefer-offline --frozen-lockfile --network-timeout 1000000
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --prefer-offline --frozen-lockfile --network-timeout 1000000 --ignore-engines
env:
YARN_IGNORE_SCRIPTS: 'true'

Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/client-android-eas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ jobs:
yarn-tools: 'true'
- name: 🧶 Yarn install
if: steps.expo-caches.outputs.yarn-workspace-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: Install eas-cli
run: npm install -g eas-cli
- name: Generate local credentials.json
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/client-ios-eas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ jobs:
yarn-tools: 'true'
- name: 🧶 Yarn install
if: steps.expo-caches.outputs.yarn-workspace-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: Install eas-cli
run: npm install -g eas-cli
- name: Build
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/create-expo-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ jobs:
yarn-workspace: 'true'
- name: 🧶 Install node modules in root dir
if: steps.expo-caches.outputs.yarn-workspace-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: 🛠 Build create-expo
run: yarn prepare
working-directory: packages/create-expo
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/development-client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ jobs:
ndk-version: ${{ matrix.ndk-version }}
- name: 🧶 Yarn install
if: steps.expo-caches.outputs.yarn-workspace-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: Init new expo app
working-directory: ../
run: yarn create expo-app ./development-client-android-test --yes
Expand Down Expand Up @@ -93,7 +94,8 @@ jobs:
yarn-workspace: 'true'
- name: 🧶 Yarn install
if: steps.expo-caches.outputs.yarn-workspace-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: Init new expo app
working-directory: ../
run: yarn create expo-app ./development-client-ios-test --yes
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/ios-unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ jobs:
native-tests-pods: 'true'
- name: 🧶 Yarn install
if: steps.expo-caches.outputs.yarn-workspace-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: 🥥 Install CocoaPods in `apps/native-tests/ios`
if: steps.expo-caches.outputs.bare-expo-pods-hit != 'true'
run: pod install
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/pr-labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ jobs:
yarn-workspace: 'true'
- name: 🧶 Install node modules in root dir
if: steps.expo-caches.outputs.yarn-workspace-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: Get the base commit
id: base-commit
run: |
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/router-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ jobs:
${{ runner.os }}-yarn-cache-

- name: Install dependencies
run: YARN_IGNORE_SCRIPTS=true yarn --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
env:
YARN_IGNORE_SCRIPTS: 'true'

- uses: actions/setup-java@v4
with:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ jobs:
yarn-tools: 'true'
- name: 🧶 Install workspace node modules
if: steps.expo-caches.outputs.yarn-workspace-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: 🧐 Check packages
run: |
echo "Checking packages according to the event name: ${{ github.event_name }}"
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/test-react-native-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ jobs:
key: ${{ runner.os }}-workspace-modules-${{ hashFiles('yarn.lock') }}
- name: 🧶 Install node modules in root dir
if: steps.workspace-modules-cache.outputs.cache-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: ⭐️ Create test-nightlies Project (New Architecture)
run: yarn prepare && bun build/index.js --expo-repo ${{ github.workspace }} --no-install ${{ runner.temp }} --enable-new-architecture true
working-directory: packages/create-expo-nightly
Expand Down Expand Up @@ -145,7 +146,8 @@ jobs:
key: ${{ runner.os }}-workspace-modules-${{ hashFiles('yarn.lock') }}
- name: 🧶 Install node modules in root dir
if: steps.workspace-modules-cache.outputs.cache-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: ⭐️ Create test-nightlies Project (New Architecture)
run: yarn prepare && bun build/index.js --expo-repo ${{ github.workspace }} --no-install ${{ runner.temp }} --enable-new-architecture true
working-directory: packages/create-expo-nightly
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/test-suite-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ jobs:
bare-expo-macos-pods: 'true'
- name: 🧶 Install node modules in root dir
if: steps.expo-caches.outputs.yarn-workspace-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: 🕵️ Debug CocoaPods lockfiles
run: git diff Podfile.lock Pods/Manifest.lock
working-directory: apps/bare-expo/macos
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/test-suite-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ jobs:
yarn-workspace: 'true'
- name: 🧶 Install node modules in root dir
if: steps.expo-caches.outputs.yarn-workspace-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: 🍏 Run iOS tests
run: ./scripts/start-ios-e2e-test.js --test
working-directory: apps/bare-expo
Expand Down Expand Up @@ -213,7 +214,8 @@ jobs:
yarn-workspace: 'true'
- name: 🧶 Install node modules in root dir
if: steps.expo-caches.outputs.yarn-workspace-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: 🤖 Run Android tests
uses: ./.github/actions/use-android-emulator
with:
Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/test-suite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ jobs:
bare-expo-pods: 'true'
- name: 🧶 Install node modules in root dir
if: steps.expo-caches.outputs.yarn-workspace-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: 🕵️ Debug CocoaPods lockfiles
run: git diff Podfile.lock Pods/Manifest.lock
working-directory: apps/bare-expo/ios
Expand Down Expand Up @@ -120,7 +121,8 @@ jobs:
yarn-workspace: 'true'
- name: 🧶 Install node modules in root dir
if: steps.expo-caches.outputs.yarn-workspace-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: 🧪 Run tests
run: ./scripts/start-ios-e2e-test.js --test
working-directory: apps/bare-expo
Expand Down Expand Up @@ -236,7 +238,8 @@ jobs:
yarn-workspace: 'true'
- name: 🧶 Install node modules in root dir
if: steps.expo-caches.outputs.yarn-workspace-hit != 'true'
run: yarn install --frozen-lockfile
# TODO(@kitten): Remove `--ignore-engines` when Node 22+ requirement is dropped again in React Native / Metro
run: yarn install --frozen-lockfile --ignore-engines
- name: 🧪 Run tests
uses: ./.github/actions/use-android-emulator
with:
Expand Down
1 change: 1 addition & 0 deletions apps/eas-expo-go/eas.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
},
"build": {
"base": {
"node": "22.17.1",
"credentialsSource": "local",
"android": {
"image": "latest",
Expand Down
2 changes: 2 additions & 0 deletions docs/constants/navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ export const general = [
makePage('guides/local-app-development.mdx'),
makePage('guides/local-app-production.mdx'),
makePage('guides/cache-builds-remotely.mdx'),
makePage('guides/prebuilt-expo-modules.mdx'),
],
{
expanded: false,
Expand Down Expand Up @@ -364,6 +365,7 @@ export const general = [
makePage('guides/typescript.mdx'),
makePage('guides/in-app-purchases.mdx'),
makePage('guides/using-push-notifications-services.mdx'),
makePage('guides/using-feature-flags.mdx'),
]),
makeSection('Troubleshooting', [
makePage('troubleshooting/overview.mdx'),
Expand Down
81 changes: 81 additions & 0 deletions docs/pages/guides/prebuilt-expo-modules.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
title: Prebuilt Expo Modules for Android
sidebar_title: Prebuilt Expo Modules
description: Learn how prebuilt Expo Modules reduce Android built times by up to 25% on your machine.
---

import { ContentSpotlight } from '~/ui/components/ContentSpotlight';

When building React Native apps, longer build times can slow down your development workflow and reduce productivity. Each time you make changes to your code, you might need to wait for the build process to complete, which can add up to significant delays.

**Starting from SDK 53**, Expo introduces prebuilt Expo Modules for Android to address this pain point. Instead of compiling Expo Modules source code from scratch during each build, your project can now use pre-compiled versions of these modules. Ultimately, this results in faster build times.

## Benefits

- **Faster local development**: Up to 25% reduction in Android build times on local machines
- **Improved developer experience**: Less waiting time during development iterations
- **Automatic optimization**: Works out of the box with new projects for SDK 53 and above

## How prebuilt Expo Modules for Android work

During your project's Android build process, look for the `[📦]` emoji prefix next to package names in the build output. This indicates that those packages are using prebuilt versions rather than being compiled from source.

For example, after creating a project with SDK 53's default template, and running the `npx expo run:android` command, you will notice the `[📦 package-name` prefix next to packages that are precompiled:

<ContentSpotlight
alt="An example of the prebuilt Expo Modules for Android build output."
src="/static/images/guides/prebuilt-expo-modules-on-android.png"
className="max-w-[280px]"
/>

## Configuration

**For SDK 53 and above, no configuration steps are required for projects** that are created with one of the available [Expo templates](/more/create-expo/#--template).

### Opting out of prebuilt Expo Modules

You can opt out of prebuilt modules. This might be required when you are modifying the module source code yourself. In this scenario, you can configure the Expo Autolinking configuration by adding `buildFromSource` to the **package.json** file:

{/* prettier-ignore */}
```json package.json
{
"name": "your-app-name",
"expo": {
"autolinking": {
"android": {
"buildFromSource": [
".*"
]
}
}
}
}
```

### Selectively opt out

You can also opt out of specific modules while keeping others prebuilt by specifying individual package names instead of the wildcard `".*"`:

{/* prettier-ignore */}
```json package.json
{
"name": "your-app-name",
"expo": {
"autolinking": {
"android": {
"buildFromSource": [
"expo-camera",
"expo-web-browser",
"expo-linking",
]
}
}
}
}
```

## Considerations

- Existing projects can benefit from this feature when upgrading to SDK 53 and above
- Performance improvements may vary based on your hardware configuration
- Current improvements on EAS Builds are more modest but provide groundwork for future caching mechanisms
66 changes: 66 additions & 0 deletions docs/pages/guides/using-feature-flags.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
title: React Native feature flag services
sidebar_title: Using feature flags
description: An overview of feature flag services available in the Expo and React Native ecosystem.
---

import { BookOpen02Icon } from '@expo/styleguide-icons/outline/BookOpen02Icon';

import { BoxLink } from '~/ui/components/BoxLink';

A feature flag (also known as a _feature gate_) is a mechanism that enables and disables features remotely. They are a safe way to rollout new features to your app users without deploying additional code. You can use them for testing in production, A/B testing, or to ship new app features such as UI elements.

## Feature flag services

The following libraries provide robust support for feature flag functionality and out-of-the-box compatibility with Expo apps using [Continuous Native Generation (CNG)](/workflow/continuous-native-generation/) and [config plugins](/config-plugins/introduction/) for seamless integration in your app.

### Posthog

[PostHog](https://posthog.com/) is an open-source product analytics platform that provides comprehensive feature flagging capabilities alongside analytics, session recordings, and A/B testing. It supports real-time feature toggles with user segmentation and the ability to roll back features instantly, making it an excellent choice for teams that want analytics and feature management in a single platform. It includes built-in A/B testing and multivariate testing functionality, allowing you to run experiments directly through feature flags while collecting detailed analytics on feature adoption and performance metrics. The service also supports bootstrap flags to eliminate loading states and improve user experience.

<BoxLink
title="PostHog React Native library"
description="Learn how to integrate PostHog feature flags in your React Native and Expo projects."
href="https://posthog.com/docs/libraries/react-native#feature-flags"
Icon={BookOpen02Icon}
/>

<BoxLink
title="PostHog feature flags tutorial"
description="Follow this step-by-step guide to implement feature flags with PostHog."
href="https://posthog.com/tutorials/react-native-analytics"
Icon={BookOpen02Icon}
/>

### Statsig

[Statsig](https://statsig.com/) is a feature management platform designed for data-driven product development that provides advanced statistical analysis, gradual rollouts, and sophisticated targeting capabilities with built-in metrics and performance monitoring for feature releases. The platform offers a robust SDK for React Native and Expo, with automatic event logging and dynamic configurations, making it particularly well-suited for teams focused on rigorous experimentation and data-driven decision-making.

<BoxLink
title="Statsig Expo integration"
description="Learn how to integrate StatSig feature flags and experiments in your Expo project."
href="https://docs.statsig.com/client/javascript-sdk/expo/#basics-check-gate"
Icon={BookOpen02Icon}
/>

### LaunchDarkly

[LaunchDarkly](https://launchdarkly.com/) is an enterprise-grade feature management platform that enables instant feature toggles and targeted rollouts with comprehensive dashboard controls, advanced user targeting, and robust experimentation tools that provide real-time flag updates. The SDK includes advanced features such as hooks for React integration, context identification and modification, comprehensive logging, support for multiple environments in development workflows, private attributes for handling sensitive data, and relay proxy configuration for enhanced security and performance.

<BoxLink
title="LaunchDarkly React Native SDK"
description="Follow this guide to integrate LaunchDarkly feature flags in your React Native and Expo projects."
href="https://launchdarkly.com/docs/sdk/client-side/react/react-native"
Icon={BookOpen02Icon}
/>

### Firebase Remote Config

[Firebase Remote Config](https://firebase.google.com/docs/remote-config) is a cloud service allows you to change the appearance and functionality of your app without requiring an app update. Remote Config values are managed through the Firebase console and accessed via a JavaScript API, which gives you full control over when and how these values affect your app. The service supports conditional targeting based on user properties, app versions, custom attributes and real-time updates.

<BoxLink
title="React Native Firebase Remote Config"
description="Learn how to integrate Firebase Remote Config from React Native Firebase library in your React Native and Expo projects."
href="https://rnfirebase.io/remote-config/usage"
Icon={BookOpen02Icon}
/>
Loading
Loading