Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7e7602c
feat: brownfield config file
Esemesek May 18, 2026
2e49823
fix: rewire config types
Esemesek May 18, 2026
de2fc04
feat: schema validation
Esemesek May 18, 2026
a54bf4a
fix: apply and log configuration
Esemesek May 18, 2026
64fb67d
chore: move files and export types
Esemesek May 19, 2026
04a9b05
chore: add unit tests and export schema.json
Esemesek May 19, 2026
f8596ee
chore: add configs to apps and support package.json typeahead
Esemesek May 22, 2026
dd4001b
Merge remote-tracking branch 'origin' into feat/brownfield-config
Esemesek May 22, 2026
4d998f3
chore: rewire schemas
Esemesek May 22, 2026
998c13d
feat: add brownie to the config
Esemesek May 26, 2026
e55b36f
docs: add documentation
Esemesek May 26, 2026
81d21bf
chore: change brownie config
Esemesek May 29, 2026
fada2ba
fix: simplify rn-brownfield name
Esemesek Jun 10, 2026
696caf9
fix: typo, import and ajv upgrade
Esemesek Jun 10, 2026
217a3f0
fix: imports and findRoot consolidation
Esemesek Jun 10, 2026
c0c7096
fix: type consolitation, schema consolidation
Esemesek Jun 10, 2026
794dcc0
Merge remote-tracking branch 'origin' into feat/brownfield-config
Esemesek Jun 10, 2026
6b0f191
chore: extract configs to android/ios keys
Esemesek Jun 17, 2026
a2d4aeb
Merge remote-tracking branch 'origin' into feat/brownfield-config
Esemesek Jun 17, 2026
c44c3f7
chore: generate schema.json
Esemesek Jun 17, 2026
e71cfa5
fix: restore overriding behavior
Esemesek Jun 17, 2026
91ebb4b
fix: set verbose corretly to logger
Esemesek Jun 17, 2026
823d349
chore: add changesets
Esemesek Jun 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/rich-turkeys-find.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@callstack/react-native-brownfield': minor
'@callstack/brownfield-cli': minor
---

Added configuration file support for react-native-brownfield packages.
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"json.schemas": [
{
"fileMatch": ["**/package.json"],
"url": "https://oss.callstack.com/react-native-brownfield/package-json.schema.json"
}
]
}
14 changes: 14 additions & 0 deletions apps/ExpoApp54/brownfield.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "https://oss.callstack.com/react-native-brownfield/schema.json",
"android": {
"moduleName": "brownfieldlib"
},
"ios": {
"scheme": "BrownfieldLib"
},
"verbose": true,
"brownie": {
"kotlin": "./android/brownfieldlib/src/main/java/com/callstack/rnbrownfield/demo/expoapp54/Generated/",
"kotlinPackageName": "com.callstack.rnbrownfield.demo.expoapp54"
}
}
10 changes: 3 additions & 7 deletions apps/ExpoApp54/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
"ci:local:e2e:ios": "bash ../../scripts/ci-local-expo54-ios-e2e.sh",
"prebuild": "expo prebuild",
"brownfield:prepare:android:ci": "cd .. && node --experimental-strip-types --no-warnings ./scripts/prepare-android-build-gradle-for-ci.ts ExpoApp54",
"brownfield:package:android": "brownfield package:android --module-name brownfieldlib --variant release --verbose",
"brownfield:publish:android": "brownfield publish:android --module-name brownfieldlib --verbose",
"brownfield:package:ios": "brownfield package:ios --scheme BrownfieldLib --configuration Release --verbose",
"brownfield:package:android": "brownfield package:android --variant release",
"brownfield:publish:android": "brownfield publish:android",
"brownfield:package:ios": "brownfield package:ios --configuration Release",
"eas:stg": "EXPO_TOKEN=$EAS_TOKEN eas update --channel production --message 'testing 1st stg channel update' --platform android"
},
"dependencies": {
Expand Down Expand Up @@ -58,9 +58,5 @@
"jest-expo": "~54.0.16",
"react-test-renderer": "19.1.0",
"typescript": "~5.9.3"
},
"brownie": {
"kotlin": "./android/brownfieldlib/src/main/java/com/callstack/rnbrownfield/demo/expoapp54/Generated/",
"kotlinPackageName": "com.callstack.rnbrownfield.demo.expoapp54"
}
}
21 changes: 15 additions & 6 deletions apps/ExpoApp55/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
"ci:local:e2e:ios": "bash ../../scripts/ci-local-expo55-ios-e2e.sh",
"prebuild": "expo prebuild",
"brownfield:prepare:android:ci": "cd .. && node --experimental-strip-types --no-warnings ./scripts/prepare-android-build-gradle-for-ci.ts ExpoApp55",
"brownfield:package:android": "brownfield package:android --module-name brownfieldlib --variant release --verbose",
"brownfield:publish:android": "brownfield publish:android --module-name brownfieldlib --verbose",
"brownfield:package:ios": "brownfield package:ios --scheme BrownfieldLib --configuration Release --verbose",
"brownfield:package:android": "brownfield package:android --variant release",
"brownfield:publish:android": "brownfield publish:android",
"brownfield:package:ios": "brownfield package:ios --configuration Release",
"eas:stg": "EXPO_TOKEN=$EAS_TOKEN eas update --channel production --message 'testing 1st stg channel update' --platform ios --environment staging"
},
"dependencies": {
Expand Down Expand Up @@ -66,8 +66,17 @@
"typescript": "~5.9.2"
},
"private": true,
"brownie": {
"kotlin": "./android/brownfieldlib/src/main/java/com/callstack/rnbrownfield/demo/expoapp55/Generated/",
"kotlinPackageName": "com.callstack.rnbrownfield.demo.expoapp55"
"brownfield": {
"brownie": {
"kotlin": "./android/brownfieldlib/src/main/java/com/callstack/rnbrownfield/demo/expoapp55/Generated/",
"kotlinPackageName": "com.callstack.rnbrownfield.demo.expoapp55"
},
"android": {
"moduleName": "brownfieldlib"
},
"ios": {
"scheme": "BrownfieldLib"
},
"verbose": true
}
}
12 changes: 12 additions & 0 deletions apps/RNApp/brownfield.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* @type {import('@callstack/react-native-brownfield').BrownfieldConfig}
*/
module.exports = {
android: {
moduleName: ':BrownfieldLib',
},
ios: {
scheme: 'BrownfieldLib',
},
verbose: true,
};
6 changes: 3 additions & 3 deletions apps/RNApp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
"ios": "yarn brownfield:package:ios && brownfield codegen && react-native run-ios",
"build:example:android-rn": "react-native build-android",
"build:example:ios-rn": "react-native build-ios",
"brownfield:package:android": "brownfield package:android --module-name :BrownfieldLib --variant release --verbose",
"brownfield:publish:android": "brownfield publish:android --module-name :BrownfieldLib --verbose",
"brownfield:package:ios": "brownfield package:ios --scheme BrownfieldLib --configuration Release --verbose",
"brownfield:package:android": "brownfield package:android --variant release",
"brownfield:publish:android": "brownfield publish:android",
"brownfield:package:ios": "brownfield package:ios --configuration Release",
"lint": "eslint .",
"start": "react-native start",
"test": "jest --config jest.config.js",
Expand Down
3 changes: 3 additions & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ dist-ssr
*.sln
*.sw?
doc_build

# Copied schema file
docs/public/schema.json
5 changes: 5 additions & 0 deletions docs/docs/docs/api-reference/_meta.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
[
{
"type": "file",
"name": "configuration",
"label": "Configuration files"
},
{
"type": "dir",
"name": "react-native-brownfield",
Expand Down
215 changes: 215 additions & 0 deletions docs/docs/docs/api-reference/configuration.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
# Configuration files

The Brownfield CLI can load configuration from a file instead of repeating the same flags on every command.
That configuration covers both `@callstack/react-native-brownfield` and `@callstack/brownie` options.

Configuration keys use camelCase names that match CLI flags inside their platform section.
For example, `--module-name` becomes `moduleName`, `--build-folder` becomes `buildFolder`, and `--use-prebuilt-rn-core` becomes `usePrebuiltRnCore`.

## Choose one configuration source

The CLI supports exactly one configuration source per project:

- `react-native-brownfield.config.js`
- `react-native-brownfield.config.json`
- `package.json` under the `react-native-brownfield` key

Do not keep more than one of these at the same time.
If the CLI finds multiple sources, it throws an error instead of guessing which one should win.

When both a config value and a CLI flag are set for the same option, the CLI flag wins.
The CLI also validates the file against the published schema and logs warnings for unknown or invalid keys.

## JavaScript config file

If you prefer a JavaScript file, create `react-native-brownfield.config.js` and export a plain object with `module.exports`:

```js
/** @type {import('@callstack/react-native-brownfield').BrownfieldConfig} */
module.exports = {
verbose: true,
android: {
moduleName: ':BrownfieldLib',
},
ios: {
scheme: 'BrownfieldLib',
},
brownie: {
kotlin:
'./android/BrownfieldLib/src/main/java/com/example/brownfield/Generated/',
kotlinPackageName: 'com.example.brownfield',
},
};
```

## JSON config file

If you want schema autocomplete and validation directly in the config file, use `react-native-brownfield.config.json`:

```json
{
"$schema": "https://oss.callstack.com/react-native-brownfield/schema.json",
"verbose": true,
"android": {
"moduleName": "brownfieldlib"
},
"ios": {
"scheme": "BrownfieldLib",
"configuration": "Release",
"usePrebuiltRnCore": true
},
"brownie": {
"kotlin": "./android/brownfieldlib/src/main/java/com/example/brownfield/Generated/",
"kotlinPackageName": "com.example.brownfield"
}
}
```

## package.json config

If you prefer to keep everything in `package.json`, place the configuration under `react-native-brownfield`:

```json
{
"name": "my-app",
"brownfield": {
"verbose": true,
"android": {
"moduleName": ":BrownfieldLib"
},
"ios": {
"scheme": "BrownfieldLib"
},
"brownie": {
"kotlin": "./android/BrownfieldLib/src/main/java/com/example/brownfield/Generated/",
"kotlinPackageName": "com.example.brownfield"
}
}
}
```

## Configuration reference

All file-based platform options mirror CLI flags, but they use camelCase property names under `android` or `ios`.

### Shared keys

| Key | Type | Description |
| --------- | --------- | --------------------------------------------------------------------- |
| `$schema` | `string` | JSON Schema URL used by editors for validation and autocomplete. |
| `verbose` | `boolean` | Enables verbose CLI logging. |
| `brownie` | `object` | Nested Brownie configuration used by `brownfield codegen`. See below. |

### Android keys

| Key | Type | Description |
| -------------------- | -------- | -------------------------------------------------------------------- |
| `android.moduleName` | `string` | Android module name used for packaging and publishing AAR artifacts. |
| `android.variant` | `string` | Android build variant, for example `debug` or `freeRelease`. |

### iOS keys

| Key | Type | Description |
| ------------------------ | ---------- | ---------------------------------------------------------------------------------------------------------------------- |
| `ios.scheme` | `string` | Xcode scheme used for packaging. |
| `ios.configuration` | `string` | Xcode build configuration, for example `Debug` or `Release`. |
| `ios.target` | `string` | Explicit Xcode target name. |
| `ios.destination` | `string[]` | One or more Xcode destinations, such as `simulator`, `device`, or full destination strings. |
| `ios.buildFolder` | `string` | Custom build output directory. By default, Brownfield uses the `.brownfield/build` path inside the iOS project. |
| `ios.archive` | `boolean` | Creates an archive build suitable for IPA export and distribution. |
| `ios.extraParams` | `string[]` | Extra arguments passed to `xcodebuild`. |
| `ios.exportExtraParams` | `string[]` | Extra arguments passed to the archive export step. |
| `ios.exportOptionsPlist` | `string` | Export options plist filename used during archive export. |
| `ios.installPods` | `boolean` | Controls automatic CocoaPods installation. Set `false` to match `--no-install-pods`. |
| `ios.newArch` | `boolean` | Controls React Native new architecture support. Set `false` to match `--no-new-arch`. |
| `ios.local` | `boolean` | Forces a local `xcodebuild` flow. |
| `ios.usePrebuiltRnCore` | `boolean` | Controls whether iOS packaging uses React Native Apple prebuilts. Omit it to keep Brownfield's version-aware defaults. |
| `ios.addSpmPackage` | `boolean` | Generates a local Swift Package Manager manifest next to the packaged XCFramework outputs. |

## Brownie configuration

The Brownie configuration lives inside the main Brownfield config under the `brownie` key.
This is the preferred format for Brownie code generation.

Currently supported Brownie keys are:

| Key | Type | Description |
| ------------------- | -------- | ----------------------------------------------------------------------- |
| `kotlin` | `string` | Directory where generated Kotlin Brownie store files should be written. |
| `kotlinPackageName` | `string` | Kotlin package name used in generated Brownie store files. |

Example inside `react-native-brownfield.config.json`:

```json
{
"$schema": "https://oss.callstack.com/react-native-brownfield/schema.json",
"brownie": {
"kotlin": "./android/BrownfieldLib/src/main/java/com/rnapp/brownfieldlib/Generated/",
"kotlinPackageName": "com.rnapp.brownfieldlib"
}
}
```

Only the Kotlin output is configurable.
Swift Brownie files are always generated to `node_modules/@callstack/brownie/ios/Generated/`.

## Migrating from legacy Brownie configuration

Legacy Brownie configuration used a top-level `brownie` block in `package.json`:

```json
{
"brownie": {
"kotlin": "./android/BrownfieldLib/src/main/java/com/rnapp/brownfieldlib/Generated/",
"kotlinPackageName": "com.rnapp.brownfieldlib"
}
}
```

The new format moves the same values under the main Brownfield config:

```json
{
"brownfield": {
"android": {
"moduleName": ":BrownfieldLib"
},
"ios": {
"scheme": "BrownfieldLib"
},
"brownie": {
"kotlin": "./android/BrownfieldLib/src/main/java/com/rnapp/brownfieldlib/Generated/",
"kotlinPackageName": "com.rnapp.brownfieldlib"
}
}
}
```

You can also migrate to a standalone config file:

```json
{
"$schema": "https://oss.callstack.com/react-native-brownfield/schema.json",
"android": {
"moduleName": ":BrownfieldLib"
},
"ios": {
"scheme": "BrownfieldLib"
},
"brownie": {
"kotlin": "./android/BrownfieldLib/src/main/java/com/rnapp/brownfieldlib/Generated/",
"kotlinPackageName": "com.rnapp.brownfieldlib"
}
}
```

Migration steps:

1. Pick one main Brownfield config source.
2. Move the legacy `package.json#brownie` values into the nested `brownie` object in that source.
3. Remove the old top-level `brownie` block from `package.json`.
4. Run `brownfield codegen` again.

Do not keep the legacy and new Brownie configuration at the same time.
If both are present, `brownfield codegen` throws an error.
If only the legacy format is present, the command still works for now, but it prints a migration warning.
6 changes: 5 additions & 1 deletion docs/docs/docs/cli/brownfield.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

The `brownfield` CLI provides utilities for building & packaging artifacts for brownfield projects that use the `@callstack/react-native-brownfield` library.

:::tip Configuration file
You can store supported `brownfield` CLI options in a project configuration file instead of passing the same flags on every command.
See [Configuration files](/docs/api-reference/configuration) for supported config sources and option names.
:::

## Usage

```bash
Expand Down Expand Up @@ -37,7 +42,6 @@ Available arguments:
| --no-install-pods | Skip automatic CocoaPods installation |
| --no-new-arch | Run React Native in legacy async architecture |
| --local | Force local build with xcodebuild |
| --verbose | Enable verbose logging |

The build directory will be placed in the `<iOS project folder>/.brownfield/build` folder by default and the build outputs (XCFrameworks) will be created in the `<iOS project folder>/.brownfield/package/build` folder:

Expand Down
5 changes: 5 additions & 0 deletions docs/docs/docs/cli/brownie.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

The `brownfield codegen` CLI command generates `@callstack/brownie` (Brownie) state management library native store types from TypeScript schema.

:::tip Configuration file
You can configure Brownie codegen from the main Brownfield config file by using the nested `brownie` object.
See [Configuration files](/docs/api-reference/configuration) for supported config sources and Brownie-specific settings.
:::

## Usage

```bash
Expand Down
Loading
Loading