NativeScope / Storage Engine
App API
Everything exported from react-native-nativescope/app, for the cases where config is not enough.
On this page
Everything here is optional. A project that only wants to inspect its storage needs none of it.
The /app entry point contains these APIs. Prefer the root config file for normal use. When normal
app code invokes an API manually, load it behind __DEV__ with require so it never enters the
production module graph. Type-only imports remain safe.
import {
defineNativeScopeConfig,
installNativeScopeDevtools,
subscribeNativeScope,
useNativeScopeSignal,
} from "react-native-nativescope/app";Reacting to changes
subscribeNativeScope
The primitive everything else is built on. Calls your listener for every change, optionally filtered, and returns an unsubscribe function.
const unsubscribe = subscribeNativeScope(
(event) => {
console.log(event.kind, event.source);
},
{ source: "studio", providerId: "mmkv" },
);The event you receive:
export type NativeScopeChange =
| {
kind: "key-value";
providerId: string;
instanceId: string;
key: string;
change: "created" | "updated" | "removed";
source: NativeScopeChangeSource;
entry: unknown | null;
timestamp: number;
}From apps/cli/app/index.d.ts
And the filter shape, where every field is optional and combines with AND:
export interface NativeScopeEventFilter {
kind?: NativeScopeChange["kind"];
providerId?: string;
instanceId?: string;
key?: string;
table?: string;
source?: NativeScopeChangeSource;
}From apps/cli/app/index.d.ts
useNativeScopeSignal
A React hook returning a number that increments on every matching change. Use it as a dependency to re-run your own read.
const signal = useNativeScopeSignal({ providerId: "mmkv", key: "user" });
useEffect(() => {
reloadUser();
}, [signal]);useStorageChanged is an alias kept for readability at call sites.
Reading storage directly
Convenience hooks that read a value and keep it fresh as the studio or the app changes it. They are for debug screens and small tools, not for production data flow.
const { value, setValue, removeValue, loading } = useInspectedAsyncStorage("token");const { value, setValue } = useInspectedMMKV<User>(mmkvInstance, "user");const { rows, loading, reload } = useInspectedSqlite<Visit>(
db,
"select * from visits where pdv = ?",
["Carrefour"],
);Each accepts an options object with a source filter, so you can react only to studio changes, only
to app changes, or both.
Installing imperatively
installNativeScopeDevtools
The manual equivalent of nativescope.config.ts. Use it when the automatic discovery cannot reach
your QueryClient.
export interface InstallNativeScopeOptions {
modules?: {
storage?: ManualNativeScopeStorageModuleConfig;
};
}From apps/cli/app/index.d.ts
if (__DEV__) {
const { installNativeScopeDevtools } = require("react-native-nativescope/app");
installNativeScopeDevtools({
modules: {
storage: { reactQuery: getQueryClient() },
},
});
}Manual installation requires an explicit QueryClient; automatic discovery and the in-app
indicator belong in nativescope.config.ts. The function returns a handle with subscribe,
getSnapshot and dispose.
defineNativeScopeConfig
Identity function that exists purely for type inference in nativescope.config.ts. See
Configuration.
Snapshots
getNativeScopeSnapshot
Returns the current version counter and the last change seen. Useful for wiring NativeScope into a
store with useSyncExternalStore.
const { version, lastEvent } = getNativeScopeSnapshot();
