A privacy-first genomic analysis app that serves as a gateway to the collaborative BioVault research network. Load your genetic data for local analysis, discover insights, and connect to the world of collaborative genomics.
- 🧬 My DNA - Load and manage genetic data files locally on your device (23andMe, AncestryDNA, etc.)
- 🔍 Insights - Run ClinVar analysis and discover genetic insights
- 🌐 Research - Connect to the BioVault collaborative genomics network
- 📊 Web-Only Features - Enhanced analytics, network participants, biobanks, pipelines, and more
- Node.js
- npm or yarn
- Expo CLI
- iOS Simulator (for iOS development)
- Android Studio/Emulator (for Android development)
Install NVM:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bashbrew install fastlane cocoapods
Get node 23:
nvm install 23.6.1
nvm alias default 23.6.1Install packages:
npm installExpo Doctor:
npx expo-doctor
iOS:
rm -rf ios
npm run cargo-ios -- ios
npm run prebuild
npm run device
Or this script:
./ios.sh-
Clone and install dependencies:
git clone <repository-url> cd biovault-app npm install
-
Start the development server:
npm run start
Option 1: Physical Device (Recommended)
- Install the BioVault Dev app from the Expo Dashboard
- Open the BioVault Dev app on your iOS device
- Scan the QR code generated by
npm run start - Your device will connect to your development server
Option 2: iOS Simulator
- Use Radon Extension for VS Code/Cursor
- Or install Expo Orbit for easy simulator management
- Press
iin the terminal after runningnpm run start
Option 1: Physical Device (Recommended)
- Download the latest BioVault APK from the Expo Dashboard
- Install the APK on your Android device
- Open the BioVault app
- Scan the QR code generated by
npm run start - Your device will connect to your development server
Option 2: Android Emulator
- Use Radon Extension for VS Code/Cursor
- Or install Expo Orbit for easy emulator management
- Press
ain the terminal after runningnpm run start
- Run
npm run start - Press
win the terminal, or - Open your browser to
http://localhost:8081(or the port shown in terminal) - The web version includes additional tabs not available on mobile
This app includes a native Rust module (modules/expo-biovault) for high-performance genome file parsing.
- Rust toolchain:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - iOS development: Xcode and iOS targets
- Android development: Android Studio, NDK, and Android targets
# iOS targets
rustup target add aarch64-apple-ios # iOS device
rustup target add aarch64-apple-ios-sim # iOS simulator
# Android targets
rustup target add aarch64-linux-android # Android ARM64
cargo install cargo-ndk # Android NDK helperFor iOS Simulator (development):
npm run cargo-ios -- --target='ios-sim'For iOS Device:
npm run cargo-ios -- --target='ios'For Android:
npm run cargo-androidThe Android build requires NDK configuration. Install via Android Studio:
- Android Studio → SDK Manager → SDK Tools → NDK (Side by side)
The build scripts automatically configure the NDK toolchain.
modules/expo-biovault/
├── expo-module.config.json # Module configuration
├── index.ts # JS exports
├── src/
│ └── ExpoBiovaultModule.ts # TypeScript definitions
├── ios/
│ ├── ExpoBiovault.podspec # iOS CocoaPods spec
│ ├── ExpoBiovaultModule.swift # iOS native implementation
│ └── rust/ # iOS Rust libraries (auto-generated)
└── android/
├── build.gradle
├── src/main/
│ ├── java/.../ExpoBiovaultModule.kt # Android native implementation
│ └── jniLibs/ # Android Rust libraries (auto-generated)
└── AndroidManifest.xml
-
Add to Rust (
biovault_rust_lib/src/lib.rs):#[unsafe(no_mangle)] pub extern "C" fn your_function(input: *const c_char) -> *mut c_char { // Your implementation }
-
Add iOS binding (
modules/expo-biovault/ios/ExpoBiovaultModule.swift):@_silgen_name("your_function") func your_function(_ input: UnsafePointer<CChar>) -> UnsafeMutablePointer<CChar>? AsyncFunction("yourFunction") { (input: String) -> String in // Convert strings and call Rust function }
-
Add Android binding (
modules/expo-biovault/android/.../ExpoBiovaultModule.kt):external fun yourFunction(input: String): String AsyncFunction("yourFunction") { input: String -> yourFunction(input) }
-
Export from module (
modules/expo-biovault/index.ts):export async function yourFunction(input: string): Promise<string> { return await ExpoBiovaultModule.yourFunction(input) }
-
Rebuild libraries:
npm run cargo-ios -- --target='ios-sim' # or 'ios' for device npm run cargo-android
"Cannot find native module" error:
- Run
npx expo prebuild --cleanto regenerate native projects - For device testing, use
npx expo run:ios --device(not Expo Dev Client)
iOS architecture mismatch:
- Use
--target='ios-sim'for simulator - Use
--target='ios'for device - The build scripts automatically copy the correct library
Android linking errors:
- Ensure NDK is installed via Android Studio
- Check that
.sofiles are inandroid/src/main/jniLibs/arm64-v8a/
- Radon Extension - Integrated simulator management for VS Code/Cursor
- Expo Orbit - Desktop app for managing simulators and builds
./cli parse --file /Users/madhavajay/dev/sequencing.com/23andme/genome_Madhava_Jay_v4_Full_20250611034825.zip --output madhava
Add your FFI
// lib.rs
#[unsafe(no_mangle)]
pub unsafe extern "C" fn process_23andme_file(// ExpoBioVaultModule.swift
@_silgen_name("process_23andme_file")
func process_23andme_file(_ inputPath: UnsafePointer<CChar>, _ customName: UnsafePointer<CChar>, _ outputDir: UnsafePointer<CChar>) -> UnsafeMutablePointer<CChar>?
///
public class ExpoBiovaultModule: Module {
public func definition() -> ModuleDefinition {
Name("ExpoBiovault")
AsyncFunction("processGenomeFile") { (inputPath: String, customName: String, outputDir: String) -> String in
let inputCString = inputPath.cString(using: .utf8)!
let nameCString = customName.cString(using: .utf8)!
let outputCString = outputDir.cString(using: .utf8)!
guard let resultPtr = process_23andme_file(inputCString, nameCString, outputCString) else {
throw Exception(name: "ProcessingError", description: "Failed to process genome file")
}
let result = String(cString: resultPtr)
free_string(resultPtr)
return result
}
}
}TypeScript:
// ExpoBioVaultModule.ts
declare class ExpoBiovaultModule extends NativeModule {
processGenomeFile(inputPath: string, customName: string, outputDir: string): Promise<string>
}
// index.ts
import ExpoBiovaultModule from './src/ExpoBiovaultModule'
export async function processGenomeFile(
inputPath: string,
customName: string,
outputDir: string
): Promise<string> {
return await ExpoBiovaultModule.processGenomeFile(inputPath, customName, outputDir)
}