---
title: "Introducing Brownie: Type-Safe Shared State for React Native Brownfield Apps"
description: "A type-safe shared state library for React Native brownfield apps. Brownie syncs native and React state from a single TypeScript schema."
url: https://www.callstack.com/blog/introducing-brownie-type-safe-shared-state-for-react-native-brownfield-apps
updated: 2026-10-24T08:39:31.918Z
---

# Introducing Brownie: Type-Safe Shared State for React Native Brownfield Apps

A type-safe shared state library for React Native brownfield apps. Brownie syncs native and React state from a single TypeScript schema.

_By Oskar Kwaśniewski, Software Developer @ Callstack · Published 2026-01-20 · Category: Brownfield_

We're excited to announce the alpha release of **Brownie** (`@callstack/brownie`), a shared state management library designed specifically for React Native brownfield applications.

## The Problem

Brownfield apps are existing native applications with React Native integration that face a fundamental challenge: **shared state**.

Your native settings screen shows the user's profile. Your React Native checkout flow needs that same user data. An authentication token refreshed in Swift needs to be available in React Native immediately. Theme preferences changed in one place should reflect everywhere.

From our experience working with clients, we've noticed a recurring pattern: **every app ends up building its own proprietary Turbo Module for data sharing**. Each team reinvents the wheel: writing custom native modules, maintaining type definitions on both sides, and constantly updating these modules as requirements change.

One of the examples is the Brownfield integration at Zalando. You can read about it[ here.](https://engineering.zalando.com/posts/2025/10/accelerating-mobile-app-development-at-zalando-with-rendering-engine-and-react-native.html)

This is the main pain point of brownfield development today. These homegrown solutions are:

- **Time-consuming to build:** Writing Turbo Modules requires native expertise on each platform.
- **Tedious to maintain:** Every schema change means updating TypeScript, Swift, and Kotlin.
- **Hard to keep in sync:** Types drift apart, leading to runtime crashes.
- **Duplicated across the industry:** Every brownfield team solves the same problem from scratch.

## Our Approach

Brownie takes a different path. Instead of treating React Native and native code as separate worlds, we created a **single source of truth** accessible from both TypeScript and Swift.

One key design decision is that **state lives on the native side**. This means your native app can read and write to the store independently of React Native. React Native can start in its own time. When it's ready, it will pick up the current state automatically.

The architecture is straightforward:

1. **Define your state shape once** in TypeScript
2. **Generate native types** automatically via CLI
3. **Access the same state** from both React Native and Swift
4. **Always retrieve** **up to date state** thanks to bi directional sync

Under the hood, state lives in a C++ layer, exposed to JavaScript via JSI and to Swift via an Objective-C++ bridge.

![](https://www.callstack.com/assets/696f8c4a0308f0f857faee2a_Introducing-Brownie_-Type-Safe-Shared-State-for-React-Native-Brownfield-Apps.jpg)

## How It Works

### 1. Define Your Store

Create a `*.brownie.ts` file with your state shape:

```typescript
// AppStore.brownie.ts
import type { BrownieStore } from '@callstack/brownie';

interface AppStore extends BrownieStore {
  counter: number;
  user: {
    name: string;
    email: string;
  };
  settings: {
    theme: 'light' | 'dark';
    notificationsEnabled: boolean;
  };
}

declare module '@callstack/brownie' {
  interface BrownieStores {
    AppStore: AppStore;
  }
}
```

## 2. Build XCFrameworks

The `brownfield` CLI handles codegen and packaging in one step:

```bash
npx brownfield package:ios --scheme YourScheme --configuration Release
```

This generates Swift types from your `.brownie.ts` files and builds everything into XCFrameworks:

- `YourScheme.xcframework` - Your React Native module
- `Brownie.xcframework` - Shared state library
- `ReactBrownfield.xcframework` - Brownfield integration
- `hermesvm.xcframework` - JavaScript engine

Drag these into your native Xcode project and set to **Embed & Sign**.

The generated Swift structs match your TypeScript schema exactly:`‍`‍

```swift
// Generated automatically
struct AppStore: Codable, Equatable {
    var counter: Double
    var user: User
    var settings: Settings
}

struct User: Codable, Equatable {
    var name: String
    var email: String
}
```

Note: Generated code is already included in `Brownie.xcframework`

### 3. Use in React Native

The `useStore` hook provides familiar React patterns with selector support:

```swift
import { useStore } from '@callstack/brownie';

function Counter() {
  const [counter, setState] = useStore('AppStore', (s) => s.counter);

  return (
    <Button
      title={`Count: ${counter}`}
      onPress={() => setState((prev) => ({ counter: prev.counter + 1 }))}
    />
  );
}
```

Selectors ensure components only re-render when their selected slice changes, just like you'd expect from a modern state library.

### 4. Use in SwiftUI

The `@UseStore` property wrapper brings the same ergonomics to SwiftUI:

```swift
import Brownie

struct CounterView: View {
  @UseStore(\\AppStore.counter) var counter

  var body: some View {
    VStack {
      Text("Count: \\(Int(counter))")

      Button("Increment") {
        $counter.set { $0 + 1 }
      }
    }
  }
}
```

KeyPath selectors provide type-safe access and optimal re-renders. The projected value (`$counter`) returns a standard SwiftUI `Binding`, so it works seamlessly with built-in controls like `Stepper`, `Slider`, and `TextField`.

### 5. UIKit Support

For UIKit apps, use the subscription-based API:`‍`

`‍`

```swift
class CounterViewController: UIViewController {
  private var store: Store<AppStore>?
  private var cancelSubscription: (() -> Void)?

  override func viewDidLoad() {
    super.viewDidLoad()
    store = StoreManager.get(key: AppStore.storeName, as: AppStore.self)

    cancelSubscription = store?.subscribe(\\.counter) { [weak self] counter in
      self?.updateLabel(counter)
    }
  }

  deinit {
    cancelSubscription?()
  }
}
```

## Why We Built This

At Callstack, we work with many teams integrating React Native into existing native apps. After seeing the same pattern repeat (teams building custom Turbo Modules for data sharing, then spending ongoing effort maintaining them), we decided to solve this once and for all.

Brownie replaces those proprietary data-sharing modules with a standardized solution. Instead of writing and maintaining your own native code for state synchronization, you define your schema in TypeScript and let Brownie handle the rest.

We wanted something that:

- **Eliminates custom native modules:** No more writing Turbo Modules just to share data.
- **Feels native on both sides:** React hooks in JS, property wrappers in Swift.
- **Is type-safe end-to-end:** TypeScript schema generates Swift types automatically.
- **Stays in sync automatically:** One schema, generated types, no manual updates.

## Current Status: Alpha (iOS Only)

This is an early alpha release. We're shipping iOS support first to gather feedback and iterate on the API before expanding to Android.

**What works today:**

- SwiftUI integration with `@UseStore` property wrapper
- UIKit integration with subscribe-based API
- React Native `useStore` hook with selectors
- Multiple stores support
- Nested objects and complex types
- Automatic codegen for Swift types
- XCFramework packaging via CLI

**Known limitations:**

- iOS only (Android coming soon)
- Full state sync on updates (partial sync optimization planned)
- APIs may change based on feedback

## We Want Your Feedback

This is an early alpha release and we're actively seeking feedback. If you try Brownie, let us know what works, what doesn't, and what's missing for your use case.

Open an issue on [GitHub](https://github.com/callstack/react-native-brownfield) with your thoughts.

Brownie is part of the [React Native Brownfield](https://github.com/callstack/react-native-brownfield) project. Check out the [documentation](https://callstack.github.io/react-native-brownfield/brownie/overview) for detailed guides on store definitions, codegen configuration, and platform-specific usage.
