Enhanced developer tools for React Native applications, supporting React Query DevTools and device storage monitoring with a beautiful native interface.
431415919-fce3cba3-b30a-409a-8f8f-db2bd28579be.mp4https://github.com/LovesWorking/RN-Dev-Tools-Example
If you need internal React Query dev tools within the device you can use my other package here!https://github.com/LovesWorking/react-native-react-query-devtools
⚠️ Important: The desktop app has currently only been tested on Apple Silicon Macs (M1/M2/M3). If you encounter issues on Intel-based Macs, please open an issue and we'll work together to fix it.
The easiest way to connect your React application to the DevTools is by installing the npm package:
# Using npm npm install --save-dev react-query-external-sync socket.io-client npm install expo-device # For automatic device detection # Using yarn yarn add -D react-query-external-sync socket.io-client yarn add expo-device # For automatic device detection # Using pnpm (recommended) pnpm add -D react-query-external-sync socket.io-client pnpm add expo-device # For automatic device detection
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { useSyncQueriesExternal } from "react-query-external-sync"; // Import Platform for React Native or use other platform detection for web/desktop import { Platform } from "react-native"; import AsyncStorage from "@react-native-async-storage/async-storage"; import * as SecureStore from "expo-secure-store"; import * as ExpoDevice from "expo-device"; import { storage } from "./mmkv"; // Your MMKV instance // Create your query client const queryClient = new QueryClient(); function App() { return ( <QueryClientProvider client={queryClient}> <AppContent /> </QueryClientProvider> ); } function AppContent() { // Set up the sync hook - automatically disabled in production! useSyncQueriesExternal({ queryClient, socketURL: "http://localhost:42831", // Default port for React Native DevTools deviceName: Platform?.OS || "web", // Platform detection platform: Platform?.OS || "web", // Use appropriate platform identifier deviceId: Platform?.OS || "web", // Use a PERSISTENT identifier (see note below) isDevice: ExpoDevice.isDevice, // Automatically detects real devices vs emulators extraDeviceInfo: { // Optional additional info about your device appVersion: "1.0.0", // Add any relevant platform info }, enableLogs: false, envVariables: { NODE_ENV: process.env.NODE_ENV, // Add any private environment variables you want to monitor // Public environment variables are automatically loaded }, // Storage monitoring with CRUD operations mmkvStorage: storage, // MMKV storage for ['#storage', 'mmkv', 'key'] queries + monitoring asyncStorage: AsyncStorage, // AsyncStorage for ['#storage', 'async', 'key'] queries + monitoring secureStorage: SecureStore, // SecureStore for ['#storage', 'secure', 'key'] queries + monitoring secureStorageKeys: [ "userToken", "refreshToken", "biometricKey", "deviceId", ], // SecureStore keys to monitor }); // Your app content return <YourApp />; }
The React Query External Sync package is automatically disabled in production builds.
// The package handles this internally: if (process.env.NODE_ENV !== "production") { useSyncQueries = require("./new-sync/useSyncQueries").useSyncQueries; } else { // In production, this becomes a no-op function useSyncQueries = () => ({ isConnected: false, connect: () => {}, disconnect: () => {}, socket: null, users: [], }); }📱 Using with Real Devices (Local Network)
When testing on real devices connected to your local network, you'll need to use your host machine's IP address instead of localhost
. Here's a helpful setup for Expo apps (contributed by ShoeBoom):
import Constants from "expo-constants"; import AsyncStorage from "@react-native-async-storage/async-storage"; import * as SecureStore from "expo-secure-store"; import { storage } from "./mmkv"; // Your MMKV instance // Get the host IP address dynamically const hostIP = Constants.expoGoConfig?.debuggerHost?.split(`:`)[0] || Constants.expoConfig?.hostUri?.split(`:`)[0]; function AppContent() { useSyncQueriesExternal({ queryClient, socketURL: `http://${hostIP}:42831`, // Use local network IP deviceName: Platform?.OS || "web", platform: Platform?.OS || "web", deviceId: Platform?.OS || "web", extraDeviceInfo: { appVersion: "1.0.0", }, enableLogs: false, envVariables: { NODE_ENV: process.env.NODE_ENV, }, // Storage monitoring mmkvStorage: storage, asyncStorage: AsyncStorage, secureStorage: SecureStore, secureStorageKeys: ["userToken", "refreshToken"], }); return <YourApp />; }
Note: For optimal connection, launch DevTools before starting your application.
['#storage', 'mmkv', 'key']
React Native DevTools works with any React-based application, regardless of platform:
If your platform can run React and connect to a socket server, it will work with these DevTools!
React Native DevTools now includes powerful storage monitoring capabilities with full CRUD operations:
['#storage', 'mmkv', 'keyName']
// In your app, use React Query to interact with storage import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; // Read from MMKV storage const { data: userData } = useQuery({ queryKey: ["#storage", "mmkv", "user"], // Data will be automatically synced with DevTools }); // Write to AsyncStorage const queryClient = useQueryClient(); const updateAsyncStorage = useMutation({ mutationFn: async ({ key, value }) => { await AsyncStorage.setItem(key, JSON.stringify(value)); // Invalidate to trigger sync queryClient.invalidateQueries(["#storage", "async", key]); }, });
The useSyncQueriesExternal
hook accepts the following options:
queryClient
QueryClient Yes Your React Query client instance socketURL
string Yes URL of the socket server (e.g., 'http://localhost:42831') deviceName
string Yes Human-readable name for your device platform
string Yes Platform identifier ('ios', 'android', 'web', 'macos', 'windows', etc.) deviceId
string Yes Unique identifier for your device isDevice
boolean No Whether running on a real device (true) or emulator (false). Used for Android socket URL handling (default: true) extraDeviceInfo
object No Additional device metadata to display in DevTools enableLogs
boolean No Enable console logging for debugging (default: false) envVariables
object No Private environment variables to sync with DevTools (public vars are auto-loaded) mmkvStorage
MmkvStorage No MMKV storage instance for real-time monitoring asyncStorage
AsyncStorage No AsyncStorage instance for polling-based monitoring secureStorage
SecureStore No SecureStore instance for secure data monitoring secureStorageKeys
string[] No Array of SecureStore keys to monitor (required if using secureStorage)
React Native DevTools is actively being developed with exciting features on the roadmap:
Stay tuned for updates!
I welcome contributions! See Development Guide for details on:
Having issues? Check these common solutions:
App Not Connecting
socketURL
is correctly pointing to localhost:42831useSyncQueriesExternal
hook is properly implementedApp Not Starting
Socket Connection Issues
enableLogs: true
for any error messagesData Not Syncing
queryClient
instanceenableLogs: true
to see connection informationAndroid Real Device Connection Issues
isDevice: true
localhost
to 10.0.2.2
for emulators onlyExpoDevice.isDevice
for automatic detection: import * as ExpoDevice from "expo-device"
DevTools App Issues
deviceId
is persistent (see below)Storage Monitoring Issues
secureStorageKeys
array is providedenableLogs: true
to see storage sync informationThat's it! If you're still having issues, visit the GitHub repository for support.
🏷️ Device Type DetectionThe isDevice
prop helps the DevTools distinguish between real devices and simulators/emulators. This is crucial for Android connectivity - the package automatically handles URL transformation for Android emulators (localhost → 10.0.2.2) but needs to know if you're running on a real device to avoid this transformation.
On real Android devices using React Native CLI and ADB, the automatic emulator detection can incorrectly transform localhost
to 10.0.2.2
, breaking WebSocket connections. Setting isDevice: true
prevents this transformation.
Recommended approaches:
// Best approach using Expo Device (works with bare React Native too) import * as ExpoDevice from "expo-device"; useSyncQueriesExternal({ queryClient, socketURL: "http://localhost:42831", deviceName: Platform.OS, platform: Platform.OS, deviceId: Platform.OS, isDevice: ExpoDevice.isDevice, // Automatically detects real devices vs emulators // ... other props }); // Alternative: Simple approach using React Native's __DEV__ flag isDevice: !__DEV__, // true for production/real devices, false for development/simulators // Alternative: More sophisticated detection using react-native-device-info import DeviceInfo from 'react-native-device-info'; isDevice: !DeviceInfo.isEmulator(), // Automatically detects if running on emulator // Manual control for specific scenarios isDevice: Platform.OS === 'ios' ? !Platform.isPad : Platform.OS !== 'web',⚠️ Important Note About Device IDs
The deviceId
parameter must be persistent across app restarts and re-renders. Using a value that changes (like Date.now()
) will cause each render to be treated as a new device.
Recommended approaches:
// Simple approach for single devices deviceId: Platform.OS, // Works if you only have one device per platform // Better approach for multiple simulators/devices of same type // Using AsyncStorage, MMKV, or another storage solution const [deviceId, setDeviceId] = useState(Platform.OS); useEffect(() => { const loadOrCreateDeviceId = async () => { // Try to load existing ID const storedId = await AsyncStorage.getItem('deviceId'); if (storedId) { setDeviceId(storedId); } else { // First launch - generate and store a persistent ID const newId = `${Platform.OS}-${Date.now()}`; await AsyncStorage.setItem('deviceId', newId); setDeviceId(newId); } }; loadOrCreateDeviceId(); }, []);
For more detailed troubleshooting, see our Development Guide.
Made with ❤️ by LovesWorking
Take a shortcut from web developer to mobile development fluency with guided learning
Enjoyed this project? Learn to use React Native to build production-ready, native mobile apps for both iOS and Android based on your existing web development skills.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4