Building Standalone Expo React Native apps locally

Use turtle to build standalone apps on local machine and for Continuous Integration (CI) setups


  1. Get a secure URL to publish project to ngrok http -host-header=""
  2. Export project to secure URL rm -rf dist/ && expo export --public-url
  3. Run project on secure local server cd dist/ && npx http-server and confirm it's running curl
  4. Build project using turtle-cli with --public-url pointing to the secure server
turtle build:android \
  --keystore-path /PATH/TO/YOUR/KEYSTORE_FILE.jks \
  --keystore-alias PUT_KEYSTORE_ALIAS_HERE

Right now when you run the expo build command, it puts you into a queue, and stores the build on Expo servers. I obviously don't want that because a queue slows me down (the build keeps failing..) and once the build is done i have to manually download it in order to be able to upload it somewhere else..

The answer to this is turtle, the standalone app builder service by Expo

npm install -g turtle-cli

turtle setup:android --sdk-version 37.0.0

On first run it'll start downloading and installing Android SDK, which will take a good while (download took 4 minutes.. install for Android SDK went on for ~70 minutes.. after which i gave gave up.. ).

Export app

Run a local server and note the URL, i used http-server whose default URL is Then use ngrok to serve that over an HTTPS link. (I tried running http-server with SSL but got a Error: self signed certificate in the end)

# run http-server
npx http-server

# run ngrok over http-server to get an HTTPS secure URL
ngrok http -host-header=""

Copy the https forwarding URL ngrok gives you. For example:

#expo export --dev --public-url
expo export --public-url

Exporting takes less than a minute..

(the --dev is supposed to get rid of --public-url must be a valid HTTPS URL. error, which it doesn't..)

├── android-index.json
├── assets
│   ├── 02bc1fa7c0313217bde2d65ccbff40c9
│   ├── 0886a6b127c6057cee83f9c65c7ffd62
│   ├── 09dd345dbd4ec5a0874841d5749ac153
│   ├── fdc01171a7a7ea76b187afcd162dee7d
│   └── ff31215218cf59699e34b7db3a479e6c
├── bundles
│   ├── android-28379830c4e0f74b22adc7bd243f273d.js
│   └── ios-802a95f67ffeeffac160346ff41e54a1.js
└── ios-index.json

Run the exported app dist/ on local server and confirm it's running ..

cd dist/
npx http-server
#cd dist/

# create a key and run http-server with SSL
#openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
#npx http-server -S -C cert.pem

NOTE: I went with publishing the app using a Netlify URL. And the site gets automatically published when i push code to the repo.. No fussing with ngrok and http-server (which are both local). This URL is called by the app, so it needs to be publicly available over the internet.. Something like is awesome


If you have previously published an Android app with Expo, get the keystore

expo fetch:android:keystore
Keystore credentials
  Keystore password: xxxxxxxxxxxxxx98a9a42e1cxxxxxxxx
  Key alias:         xxxxxxxxxxxxxxxxxxxxxnBwcmVhY3Ruxxxxxxxx
  Key password:      xxxxxxxxxxxxxxxxxxxxxx9bcxxxxxxx

  Path to Keystore:  /media/aamnah/Files/Sites/fppreactnative/fppreactnative.jks

From the project root, run the following

turtle build:android \
  --keystore-path /PATH/TO/YOUR/KEYSTORE/XXXXXXXX.jks \
  --keystore-alias PUT_KEYSTORE_ALIAS_HERE
  • The --public-url here is the secure URL we git with ngrok which is forwarding to https-server running inside dist/
  • This will generate an app bundle .aab file. To get an APK, pass it as a flag --type apk

Build failed after 10 minutes.. =( Removed ~/.turtle/workingdir and ran the build again. Build failed again because of node version incompatibility. Upgraded node and ran the build again.. Build failed because of an invalid keystore error.. Fixed that, ran the build again. Success! Took around 5 minutes to give me an app bundle .aab file. Yesssss!

The build is saved inside a folder called expo-apps inside the user's Home directory (Ubuntu).

Java 8

You need to install Java 8 SDK as turtle-cli only works with JDK 8. I had 11.0.7 (openjdk) installed on my Ubuntu machine..

screenshot - Turtle JDK 8 Error

The easy way is to install openjdk and change your Java version

sudo apt install -y openjdk-8-jdk-headless openjdk-8-jre
sudo update-alternatives --config java

screenshot - terminal change java sdk version

The more complicated way is to download it from the Oracle website. See [this gist] for instructions on how to download without having to create and login to an Oracle account. Basically, you go to the downloads page, click the download you want, accept the checkbox for license, and instead of clicking the green download button you copy link location, and then you change the otn part to otn-pub and open that link in order to download.. (blekh)


ERROR: Failed to build standalone app
  err: Error: --public-url is invalid - only HTTPS urls are supported

Using --dev exports the app but i kept getting error when trying to build standalone app with turtle. Ended up installing http-server in order to configure SSL.

Jul 1 11:22:10 turtle[424759] ERROR: Failed to build standalone app
  err: Error: Couldn't find app.json.
      at Object.loadAppJSON (/home/aamnah/.nvm/versions/node/v12.18.0/lib/node_modules/turtle-cli/src/bin/utils/project.ts:14:11)
      at /home/aamnah/.nvm/versions/node/v12.18.0/lib/node_modules/turtle-cli/src/bin/utils/builder.ts:77:23
      at Command.<anonymous> (/home/aamnah/.nvm/versions/node/v12.18.0/lib/node_modules/turtle-cli/src/bin/index.ts:23:12)
  platform: "android"

Turtle only works with app.json and not app.config.js or app.config.ts. Changed back to app.json and it worked.


Please note that this site and the posts on it are, and will always be, a work in progress. If i waited for perfection, i’d never get anything done.