Back to Insights
Wellness & Tech

Building a Fitness App with React Native: A Complete Guide

Learn how to build a cross-platform fitness app with React Native and Expo. Covers architecture, wearable integration, offline support, and real-time workout tracking.

Marketplace Labs Team13 May 20265 min read
React NativeFitness AppMobile DevelopmentExpoHealthKitGoogle Fit

Building a Fitness App with React Native: A Complete Guide

Fitness apps have unique technical requirements that most mobile apps don't face: real-time data during workouts, wearable device integration, background tracking, and users who won't tolerate lag when they're mid-rep. Here's how to build one properly with React Native.

Why React Native for Fitness Apps?

React Native with Expo gives you native performance on both iOS and Android from a single codebase. For fitness apps specifically:

  • Native modules for HealthKit (iOS) and Health Connect (Android)
  • Background execution for step counting and GPS tracking
  • Smooth animations at 60fps for workout timers and progress charts
  • 50% less development cost compared to building native apps separately

The apps we build at Marketplace Labs typically ship to both platforms in 3-4 months, versus 6+ months for separate native builds.

Core Architecture

A fitness app needs three layers working together:

1. Real-Time Workout Engine

During active workouts, users expect instant feedback. Structure your state management accordingly:

// Use Zustand for workout state - simpler than Redux, fast enough for real-time
import { create } from 'zustand';

interface WorkoutState {
  isActive: boolean;
  elapsedSeconds: number;
  currentHeartRate: number | null;
  reps: number;
  sets: CompletedSet[];
  startWorkout: () => void;
  recordRep: () => void;
  updateHeartRate: (bpm: number) => void;
}

export const useWorkoutStore = create<WorkoutState>((set) => ({
  isActive: false,
  elapsedSeconds: 0,
  currentHeartRate: null,
  reps: 0,
  sets: [],
  startWorkout: () => set({ isActive: true, elapsedSeconds: 0 }),
  recordRep: () => set((state) => ({ reps: state.reps + 1 })),
  updateHeartRate: (bpm) => set({ currentHeartRate: bpm }),
}));

2. Health Data Sync Layer

Never call HealthKit or Google Fit directly from components. Create an abstraction layer:

// services/healthService.ts
import AppleHealthKit from 'react-native-health';
import { initialize, readRecords } from 'react-native-health-connect';

export const healthService = {
  async getStepsToday(): Promise<number> {
    if (Platform.OS === 'ios') {
      return this.getStepsFromHealthKit();
    }
    return this.getStepsFromHealthConnect();
  },

  async syncWorkout(workout: CompletedWorkout): Promise<void> {
    // Write to both platforms' health stores
    // This ensures the workout appears in Apple Health / Google Fit
  },
};

3. Offline-First Data Layer

Gym basements have terrible signal. Your app needs to work offline:

// Use WatermelonDB for local-first storage
import { Database } from '@nozbe/watermelondb';
import SQLiteAdapter from '@nozbe/watermelondb/adapters/sqlite';

// Workouts are saved locally first, synced when online
const adapter = new SQLiteAdapter({
  schema,
  migrations,
  jsi: true, // Enable JSI for better performance
});

Wearable Integration

Apple Watch

For Apple Watch integration, you have two options:

  1. HealthKit only - Read data the Watch already collects (steps, heart rate, workouts)
  2. watchOS companion app - Build a dedicated Watch app for real-time control

Most fitness apps start with option 1. It's simpler and covers 80% of use cases:

import AppleHealthKit, { HealthKitPermissions } from 'react-native-health';

const permissions: HealthKitPermissions = {
  permissions: {
    read: [
      AppleHealthKit.Constants.Permissions.HeartRate,
      AppleHealthKit.Constants.Permissions.StepCount,
      AppleHealthKit.Constants.Permissions.Workout,
    ],
    write: [AppleHealthKit.Constants.Permissions.Workout],
  },
};

AppleHealthKit.initHealthKit(permissions, (error) => {
  if (error) {
    console.log('HealthKit permission denied');
    return;
  }
  // Ready to read/write health data
});

Bluetooth Heart Rate Monitors

For Polar, Wahoo, and other Bluetooth HR monitors:

import { BleManager } from 'react-native-ble-plx';

const HEART_RATE_SERVICE = '180D';
const HEART_RATE_MEASUREMENT = '2A37';

// Scan for HR monitors and subscribe to measurements

Background Tracking

Step counting and GPS tracking need to continue when the app is backgrounded:

// app.json (Expo)
{
  "expo": {
    "ios": {
      "infoPlist": {
        "UIBackgroundModes": ["location", "fetch"],
        "NSMotionUsageDescription": "Used to count steps during workouts"
      }
    },
    "android": {
      "permissions": [
        "ACTIVITY_RECOGNITION",
        "ACCESS_BACKGROUND_LOCATION",
        "FOREGROUND_SERVICE"
      ]
    }
  }
}

On Android, you'll need a foreground service with a persistent notification. On iOS, use significant location changes or the pedometer API.

Performance Optimisation

Fitness apps live or die by performance. Users notice lag during workouts.

Workout Timer

Don't use setInterval for workout timers - it drifts. Use the device clock:

const [startTime] = useState(Date.now());
const [elapsed, setElapsed] = useState(0);

useEffect(() => {
  const interval = setInterval(() => {
    setElapsed(Math.floor((Date.now() - startTime) / 1000));
  }, 100); // Update frequently, calculate from real time

  return () => clearInterval(interval);
}, [startTime]);

Chart Rendering

For workout charts with hundreds of data points, use react-native-skia instead of SVG-based libraries:

import { Canvas, Path, Skia } from '@shopify/react-native-skia';

// Skia renders charts at 60fps even with 1000+ data points

Common Pitfalls

1. Ignoring Android fragmentation - Health Connect is only available on Android 14+ (or as a separate app on older versions). Have a fallback.

2. Not handling permission denial gracefully - Users who deny health permissions can still use the app for manual logging.

3. Draining battery with GPS - Use significant location changes for casual tracking, high-accuracy GPS only during active outdoor workouts.

4. Forgetting timezone handling - A user who travels and works out will have confusing data if you store everything in local time.

What It Costs

A fitness app with workout tracking, health integration, and basic social features typically takes:

  • MVP (3-4 months): £40,000 - £60,000
  • Full-featured (5-7 months): £70,000 - £120,000

The range depends on whether you need a Watch app, custom wearable integrations, or social/community features.

Next Steps

If you're planning a fitness app, the first decision is scope. Start with:

  1. One core workout type (strength, running, or HIIT)
  2. Basic health data integration (steps, workouts)
  3. Simple progress tracking

Then expand based on user feedback. We've seen too many fitness apps try to do everything at launch and ship nothing.

Need help scoping or building? Get in touch - we've shipped fitness apps for gyms, personal trainers, and wellness startups.