Accelerating continuous integration with Fingerprint, Repack in EAS Workflows
Product••6 minutes read
Kudo Chien
Engineering
Cut CI build times by up to 78% with Expo’s Fingerprint + Repack workflow. Skip native builds and ship faster with smarter automation.

Build speed is a critical factor in development productivity. At Expo, we’re constantly optimizing our pipelines to deliver faster, more reliable feedback. One of our most powerful internal workflows combines fingerprinting and repacking to dramatically reduce build times—especially for CI smoke tests and internal QA. Below, you’ll find definitions, performance metrics, a real-world case study, and a complete implementation example.
How the Fingerprint, Repack workflow works
This is a quick summary of the key steps involved in the workflow so you can see how these tools work together to avoid unnecessary native builds.
- The
fingerprintjob generates a deterministic hash of your app’s native state for each platform. get-buildchecks whether an existing build matches the hashes for each platform.- If a matching build exists, the
repackjob copies it and replaces its metadata + JavaScript bundle. - If no matching build exists, the workflow triggers a
build. - Finally, end-to-end tests (eg: with
maestro) are run against the either the repacked or freshly built apps.
What is fingerprinting?
@expo/fingerprint produces a single hash that represents every native dependency and configuration in your project. With it, your CI can answer questions like:
- Were native files modified? Only trigger native builds when necessary.
- Which native files were modified? By default, a fingerprint is stored on EAS for every build and update, and that you can compare fingerprints to understand what changed in your native runtime.
- Can I deploy my code with EAS Update to an existing release? Determine runtime compatibility to ensure your changes run safely in production.
Learn more in our “Fingerprint Your Native Runtime” blog post.
What is repacking?
Originally built in 2024 to speed up our App.js keynote demo, we define repacking as taking an existing binary and injecting a new JavaScript bundle and associated metadata—skipping the entire native compilation step (”everything old is new again”). When paired with Fingerprint, Repack only runs if your hash matches a previous build, cutting full-build time down to approximately the time it takes to calculate the fingerprint and bundle your JavaScript app.
You can think of repacking as a particularly high level type of caching, where the fingerprint is the cache key and the entire native build is cached — only the JavaScript bundle and metadata are updated.
Performance improvements with repacking
The improvements you should expect will depend on your app build time. You can estimate this by looking at the duration of your “Run fastlane” or “Run gradlew” steps on EAS Build. The following is an example of an improvement observed in a large, real-world application.
- Average duration of a full native build: ~23 mins
- Average duration of repacking: ~5 minutes
That’s roughly a 78% reduction in CI build time—cutting 18 minutes off of the time it would take for you to get feedback from an end-to-end test run.
Repacking workflow case study
A client of ours (who we cannot name) and Infinite Red reached out to us after identifying repacking as a potential time-saver for their CI processes. Working in partnership with our team, they successfully implemented this workflow for their PR smoke tests, cutting job run times approximately in half. That’s half as much time waiting on CI to run, which unblocks engineers and accelerates their development cycles.
Based on their success, we’ve now published repack as a pre-packaged job in EAS Workflows.
Ideal use cases for repacking
- PR smoke testing: Validate core functionality immediately after each commit.
- Internal QA: In roughly the same amount of time that it takes to publish an update with EAS Update, you can repack an existing build that launches directly into the version of your app that you’d like to test (rather than downloading an existing build with an older JavaScript app version and loading an update in it).
When not to use repacking
App Store submissions: Production builds should go through the full build pipeline for correct symbolication and signing. Tools like Sentry may not be able to locate symbol files in repacked binaries. We may be able to improve repacking to support this in the future, but it is not currently planned.
Example workflow configuration
Here’s how you can integrate fingerprinting and repacking directly into your .eas/workflows/ci-fingerprint-repack.yml using pre-packaged jobs. This setup ensures that every pull request benefits from faster, smarter CI.
name: ci-fingerprintjobs:fingerprint:id: fingerprinttype: fingerprintandroid_get_build:needs: [fingerprint]id: android_get_buildtype: get-buildparams:fingerprint_hash: ${{ needs.fingerprint.outputs.android_fingerprint_hash }}platform: androidandroid_repack:needs: [android_get_build]id: android_repackif: ${{ needs.android_get_build.outputs.build_id }}type: repackparams:build_id: ${{ needs.android_get_build.outputs.build_id }}android_build:needs: [android_get_build]id: android_buildif: ${{ !needs.android_get_build.outputs.build_id }}type: buildparams:platform: androidprofile: preview-simulatorandroid_maestro:after: [android_repack, android_build]id: android_maestrotype: maestroimage: latestparams:build_id: ${{ needs.android_repack.outputs.build_id || needs.android_build.outputs.build_id }}flow_path: ['maestro.yaml']ios_get_build:needs: [fingerprint]id: ios_get_buildtype: get-buildparams:fingerprint_hash: ${{ needs.fingerprint.outputs.ios_fingerprint_hash }}platform: iosios_repack:needs: [ios_get_build]id: ios_repackif: ${{ needs.ios_get_build.outputs.build_id }}type: repackparams:build_id: ${{ needs.ios_get_build.outputs.build_id }}ios_build:needs: [ios_get_build]id: ios_buildif: ${{ !needs.ios_get_build.outputs.build_id }}type: buildparams:platform: iosprofile: preview-simulatorios_maestro:after: [ios_repack, ios_build]id: ios_maestrotype: maestroimage: latestparams:build_id: ${{ needs.ios_repack.outputs.build_id || needs.ios_build.outputs.build_id }}flow_path: ['maestro.yaml']
Conclusion
By using repacking in your testing and QA workflows, you can:
- Dramatically reduce CI build times
- Trigger full native builds only when needed
- Deliver faster feedback to developers and testers
While full production builds still require Expo’s standard pipeline, this combo is a game-changer for internal testing and PR validation. Give it a try in your next EAS Workflow and spend less time sword fighting.


