Continuous Native Generation (CNG)

Edit this page

Learn about Continuous Native Generation (CNG) and how it works.


A single native project on its own is complicated to maintain, scale, and update. In a cross-platform app, you have multiple native projects that you must maintain and keep up to date with the latest operating system releases to avoid falling too far behind in any third-party dependencies.

As your project grows, the complexity involved with each third-party dependency increases and makes the app nearly impossible to upgrade — this drastically slows down developer momentum, discourages adding complex native functionality, and leads to less powerful apps. To combat these issues, we formalized a process called Continuous Native Generation (CNG).

Continuous Native Generation is an abstract concept that describes the process of generating ephemeral native projects from a set of inputs. The inputs are typically a combination of configuration and code, and the output is a native project that can be compiled into a native app. We coined this term to describe the process used by Expo Prebuild to generate native projects for React Native apps, however, the concept is not limited to React Native or cross-platform apps.

Usage in React Native

Any React Native app can leverage Continuous Native Generation by using Expo Prebuild. This enables you to automate upgrading React Native, installing/uninstalling libraries, white-labeling at scale, sharing config across multiple apps, generating assets, reducing orphaned code, and more — generally, it allows you to build more powerful apps, at larger scales, without compromising on iteration speed.

Expo as a framework enables Continuous Native Generation by combining the following tools:

  1. The app config file.
  2. Arguments passed to the npx expo prebuild command.
  3. Version of expo that's installed in the project and corresponding prebuild template.
  4. Autolinking, for linking native modules found in the package.json.
  5. Native Subscribers, for reducing native code side-effects in entry files.
  6. EAS Credentials for code signing additional targets and entitlements.

This boils down to a workflow where a user can express any native application with the app config and generate that project continuously — by running npx expo prebuild.

Community adoption

Many complex libraries and services already support CNG via Expo Prebuild such as, MapBox, OneSignal, Stripe, and React Native Firebase.

Libraries that don't have first-party integration are also supported in the community Config Plugins repository.

Expo Config Plugins have first-class support for building locally and adding to your project without any third-party intervention or npm publishing. This enables you to move fast and patch things!

Note: npm downloads do not exactly reflect the number of users. However, it provides a rough estimate of adoption.

Adoption by library authors

React Native libraries can adopt CNG in various ways depending on the complexity of their libraries. We've outlined different scenarios for library adoption:

  • No native code or configuration side-effects: Libraries without native code or configuration side-effects, such as react-native-blurhash, can seamlessly integrate with npx expo prebuild. They can rely on Node Module Resolution and Expo Autolinking to link into the native project without requiring any additional configuration.

  • Native code with no additional setup after install: Libraries with native code can often be installed and linked automatically with Expo Autolinking which runs before the native app is built.

  • Additional configuration side-effects and setup: Libraries that require additional configuration side-effects can adopt CNG by creating Expo Config Plugins for their libraries. This approach enables library authors to automate adding values such as permission messages to the Info.plist, or injecting targets in the Xcode project.

  • Libraries Dependent on Native Runtime Hooks: Libraries that depend on specific native runtime hooks, such as intercepting the initial launch URL via the AppDelegate, MainActivity, MainApplication, and so on, can utilize Lifecycle listeners to minimize the side-effects of their library.

While library authors' adoption of CNG is not a prerequisite for using npx expo prebuild, it significantly enhances the user experience. If a library author has not yet adopted CNG, users can still use npx expo prebuild by creating local Config Plugins to modify the native generation pipeline. This flexibility ensures that the adoption of CNG is accessible and beneficial to all users within the React Native community.

Success

CNG is designed to empower developers to build better apps than they normally could, by dividing configuration into testable and maintainable pieces. This allows developers to build more powerful apps without compromising on iteration speed.

This pattern has been proven to work in the React Native community in the following ways.

Upgrades

React Native developers who don't use Continuous Native Generation have reported that upgrading their apps to the latest version of React Native is the number one weakness of the library as per React Native Survey (2022).

When using CNG, the upgrade process simply involves upgrading the npm dependencies, app config, and re-running npx expo prebuild --clean.

Features

The community has been able to convert difficult native features into simple configuration files, which has allowed developers to build more powerful apps without compromising on iteration speed.

Here are a few impressive examples:

  • iOS Safari Extensions — We can see the process of creating a Safari Extension for iOS, which is a notoriously difficult feature to implement, boiled down to a couple of lines of JSON.
  • iMessage Sticker App — This Expo Config Plugin can generate an entire iMessage Sticker App from a JSON object.
  • Cross-platform End-2-End testing — Configure native apps to support E2E testing with Detox in a single-line.
  • Entire Firebase suite — Here you can see the entire native Firebase suite going from a multi-step native process across multiple IDEs, down to basic JSON configuration.
  • Cross-platform Home screen Widgets — This Expo Config Plugin can generate a home screen widget for Android and iOS.
  • Notification extension and code signing — This Expo Config Plugin not only generates a notification extension target on iOS. However, it also augments the EAS credentials service to keep zero-config code signing working.
  • Apple App Clips — This Expo Config Plugin takes the process of generating an Apple App Clip from a multi-step process, ranging across multiple targets, and shakes it down to a single line ["react-native-app-clip", { "name": "My App Clip" }].

At any point, these features can be easily added, and just as easily removed, without any side effects. CNG allows developers to experiment with complex features, and iterate on them quickly without worrying about the long-term maintenance costs or potential orphaned code in their project or uncommitted native caches.

This nets out to better apps, built faster.

Frequently Asked Questions

Is Continuous Native Generation (CNG) limited to React Native projects?

No, CNG is a versatile pattern that can be applied to any native project. While Expo Prebuild is a tool that implements CNG specifically for React Native projects, the concept itself is not limited to this framework.

Can CNG be used for operating systems other than Android and iOS?

Absolutely! CNG is an abstract concept that can be applied to any operating system. Take Expo for example, although Expo Prebuild officially implements CNG for Android and iOS, it also provides abstract platform support for users to create implementations for additional platforms.

Is using Expo a requirement for CNG?

Not at all. CNG is an open pattern that can be adopted by any community. We've defined the pattern abstractly to help other communities understand how they can adopt CNG for their own projects.

How does CNG compare to web development patterns such as Static Site Generation (SSG)?

CNG shares similarities with SSG in that it generates a project from a set of inputs. However, CNG differs from SSG in its output; it generates native runtime code instead of static website code. This means the native project is generated on-demand, and the generated source code and configuration are discarded once the native project is compiled into a native app.

Is it possible to use CNG with an existing brownfield project?

CNG is designed to manage the entire state of a native project continuously. As a result, it's not intended for use with existing brownfield projects. However, you can use CNG to generate a new native project, which can then be integrated into an existing brownfield project.