Note: this post was originally published on February 28, 2019, and subsequently updated on March 14, 2019 to reflect improvements to the workflow.

Starting today, you can use as little or as much of the Expo SDK as you like in any React Native app. We’ve spent a lot of time building and maintaining these cross-platform APIs for native features, and we’re happy to finally share them with the entire React Native ecosystem and to continue evolving them as a together.

The two main workflows for Expo going forward are referred to as “Managed” and “Bare”. Managed apps are built with the expo-cli , the Expo client on your mobile device, and our various services: push notifications, the build service, and over-the-air (OTA) updates. Expo tries to manage as much of the complexity of building apps for you as we can, so we call it the Managed workflow. Bare apps, on the other hand, give all of the control (and the complexity that comes with it) to the developer.

TL;DR: follow “Hello World” guide for bare projects in the Expo docs to do the thing described in the title.

We’re calling this initial release a preview because it’s not as streamlined as we’d like it to be, but we wanted to get these features into users’ hands as soon as possible as they’re already a big improvement. More about the future under “What’s next”.

Introducing Unimodules

React Native packages have traditionally all been small monoliths. If they need to interact with the filesystem or permissions, they’ll each implement the logic for this in their own way. The result is unnecessary duplication of effort, bugs, and incomplete and inconsistent behavior. Because Expo was originally built as a monolith, it was natural for us to build and depend on a more general solution for these fundamental building blocks of our APIs. When it came to splitting Expo apart to enable developers to cherry-pick portions of the SDK as needed, we were faced with a decision: take a step backwards and provide ad hoc implementations of these building blocks in each module? Or build a tool that allows modules to cleanly interact with one another?

The result of this effort is a project called “Unimodules”. Unimodules is a toolchain for building modular React Native plugins that can interact with one another. I’ll save the details for another post, but we’re excited about the potential this has to improve various difficulties that exist with native modules in React Native. It also opens up the possibility of sharing implementations of cross-platform APIs with other adjacent communities — we demonstrated this by making a Unimodule adapter for Flutter and publishing a few Flutter packages to use the Expo SDK! (Read “How to use Expo Unimodules in Flutter” if you’re curious.)

Let’s get to the real meat of this though: how do you use these APIs in your app?

Installing a Unimodule in a bare React Native app

1. Get react-native-unimodules

If you create a React Native project through react-native init or with another tool like ignite-cli , then you’ll need to add the react-native-unimodules package to your project and configure it first: follow the instructions in the README. This package provides functionality that’s commonly depended on by other modules (e.g. Permissions , Constants , and FileSystem ): it's a platform on which to build other modules. You have to do this only once per app.

If you create a bare React Native project through expo-cli by running expo init and choosing a Bare template, your project will have react-native-unimodules installed and configured for you. You can run this project by using react-native run-ios or react-native run-android rather than expo start .

2. Find and install the packages that you want

Scroll through the API reference in the Expo documentation and find the API that you’d like to add to your project. Jump to the Installation section and follow the link to the installation instructions for bare React Native. Most packages have the same simple set of installation instructions, but in a few cases you’ll need to add a bit of code in addition to configuring the dependencies. Now, use it in your app!

It’s worth noting that certain APIs included in the SDK are not Unimodules: MapView is just react-native-maps , SVG is react-native-svg , GestureHandler is react-native-gesture-handler , and takeSnapshotAsync is a wrapper around react-native-view-shot . All of these APIs are installable using the instructions in their corresponding READMEs.

Installing a Unimodule in a Managed app

For now, this remains the same as always: everything is available out of the box through the expo package.

When you choose Managed in expo init , you will get a project that you can open in the Expo client and it’ll include the expo package, which is a collection of packages that make up the Expo SDK. For example, it depends on and re-exports expo-permissions , expo-file-system , expo-web-browser , and other modules. In the near future, the expo package will include only a minimal core of packages, similar to react-native-unimodules , and to use others in your app you’ll need to install the npm package, but no native configuration will be required. This will result in smaller bundle sizes and faster build times because you include only the code that you use in your app.)

Other folks in the community may begin to build their native modules around the Unimodule tooling. We can’t support arbitrary native modules in the Expo client while also distributing it through the App Store, so you won’t be able to install these in Managed apps today.

Unimodules that the Expo team designs and authors will be known collectively as Foundation. We’re working on adding web and TypeScript support for all Foundation Unimodules — more on this coming soon.

The future of ExpoKit

In my post ExpoKit 2019, I wrote that we planned to continue supporting and improving the ExpoKit workflow. This is the first result of evaluating this position. By installing Unimodules in a bare React Native app today, you can already get very close to what’s possible with ExpoKit. What’s missing is support for over-the-air updates and notifications through Expo’s updates and notifications services; background tasks with TaskManager , AppLoading and SplashScreen ; and our experimental AR APIs. We're already working on bringing background tasks to bare React Native and will work on over-the-air updates and notifications Unimodules soon afterwards.

What’s next

Autoinstall Unimodules

Update: on March 14, 2019 we released this feature! Use react-native-unimodules and most of the installation of Unimodules is handled for you. Original text: We’re really excited about what’s coming next — there’s already an open pull request to automatically install Unimodules to iOS and Android projects, so that in most cases you won’t have to do much more than install the package from npm. We want to make Unimodules as easy to install as possible.

We’re also looking forward to getting our over-the-air updates and background tasks APIs into the hands of the bare workflow users. Lastly, we want to help others use Unimodules infrastructure for their own libraries when it would benefit them, so we will document how to build your own Unimodule from scratch and how to convert an existing React Native library.

Let us know what you think

The easiest way to give this a try is to follow the “Hello World” guide for bare projects in the Expo docs. Let us know what you think on the forums, or on the dystopian internet hellscape we all lovehate — Twitter.

Big thanks to Software Mansion who made this all happen, in particular Stanisław Chmiela and Tomasz Sapeta.