MapLibre React Native provides React Native bindings to MapLibre Native rendering engines for Android & iOS. It wraps native MapView components, camera controls, data sources, and style layers as React components, bridging JavaScript props to native view properties through React Native's new architecture (Fabric + TurboModules).
Key Facts:
- Current version v11: Only supports React Native's new architecture (Fabric/TurboModules)
- Native SDKs: MapLibre Native iOS v6 (
MapLibreReactNative.podspec), Android v12 (android/gradle.properties) - Runtime: React Native >=0.80, Node v24 (
.nvmrc), Yarn 4 (corepack) - Languages: TypeScript (shared), Objective-C (iOS), Kotlin (Android)
- MapView: Root map container, wraps native MapLibre view via Fabric codegen (
MapViewNativeComponent.ts) - Camera: Controls viewport (zoom, bearing, pitch, center), uses imperative ref API
- Sources: Data providers (GeoJSONSource, VectorSource, RasterSource, ImageSource) - children of MapView
- Layers: Visual representation (FillLayer, LineLayer, SymbolLayer, etc.) - children of Sources
- Annotations: User interaction elements (PointAnnotation, MarkerView, Callout)
- Modules: Native modules for offline, location, logging, snapshots
- Fabric Components: Components using new arch have
*NativeComponent.tsfiles withcodegenNativeComponent - Turbo Modules: Modules using new arch have
Native*Module.tsfiles withTurboModuleRegistry.getEnforcing - Accompanied Modules for Components: Components like
MapViewhaveMapViewModulefor imperative methods - Style Transformation: Props → native format via
transformStyle()inutils/StyleValue - Children as Config: Sources contain Layers, Layers inherit sourceID from parent
- Ref-based Imperative API: MapView, Camera, GeoJSONSource expose methods via
useImperativeHandle
scripts/codegen.ts generates from MapLibre style spec + TSDoc comments:
- Native style classes: iOS
.h/.m, Android.javaincomponents/layers/style/ - TypeScript types:
src/types/MapLibreRNStyles.ts(layer styles, expressions) - Documentation:
/docs/content/components/and/docs/content/modules/
NEVER edit generated files - they have header comments indicating source.
- Strict mode enabled (
tsconfig.json) - no implicit any, unused vars, etc. - Export pattern: Named exports only, barrel exports in
index.ts - Props: Use
interfacewithPropssuffix (e.g.,MapViewProps,CameraProps) - Types: Use
typefor unions/mapped types,interfacefor object shapes - Ref types: Pattern:
ComponentRef(e.g.,MapViewRef,CameraRef) - Native props: Separate
NativePropsinterface for codegen-compatible types - Null safety: Always check
useRefvalues before use, use optional chaining
- Native modules:
MLRNprefix (e.g.,MLRNMapView,MLRNCamera) - Files: PascalCase for components, camelCase for utils/hooks
- Props: Descriptive, follows MapLibre terminology (e.g.,
bearing,pitch) - Events:
onprefix (e.g.,onPress)
- Mock native modules in
src/__tests__/__mocks__ - Use React Native Testing Library patterns
- Test component prop handling, not native behavior
- E2E tests in Maestro verify native integration
In Jest Tests (src/__tests__/):
@maplibre/maplibre-react-native: Public exports@/*: Internal exports- Configured in
jest.config.ts
In Example Apps (examples/shared/):
@/*: Referencesexamples/shared/src/*- Configured in
tsconfig.json,metro.shared.js, andbabel.shared.js
- Create component in
src/components/(e.g.,MyComponent.tsx) - If using Fabric: Create
MyComponentNativeComponent.tswithcodegenNativeComponent - Add exports to
src/index.ts - Add TSDoc comments (triggers codegen for docs)
- Create native implementations:
- iOS: ViewManager in
ios/components/ - Android: ViewManager in
android/src/main/java/org/maplibre/reactnative/components/
- iOS: ViewManager in
- Add unit tests in
src/__tests__/ - Add example scene in
examples/shared/src/examples/
- DON'T edit generated files in
src/types/MapLibreRNStyles.tsor native style classes - DO edit templates in
scripts/templates/if changing codegen logic - Run
yarn codegento regenerate - Run
yarn prepackto rebuild types
- iOS: Edit files in
ios/components/orios/modules/ - Android: Edit files in
android/src/main/java/org/maplibre/reactnative/ - Rebuild native apps to test changes
- Consider if changes affect public API (requires TypeScript type updates)
- Component/Module docs: Edit TSDoc comments in source files, run
yarn codegen - Guide docs: Edit markdown files in
docs/content/ - README: Edit
README.mdorCONTRIBUTING.mddirectly
Prerequisites: Node 24 (.nvmrc), corepack-enabled yarn 4, Java 21, Android SDK (API 35)
Initial setup:
corepack enable
yarn install # Always from root - installs all workspacesiOS only: macOS, Xcode, CocoaPods (via bundler)
yarn lint # All linters for TypeScript code (required before commit, when .ts or .tsx files changed)
yarn lint:tsc # TypeScript (lib + examples + docs)
yarn lint:eslint # ESLint (0 warnings required)
yarn test # Jest unit tests
yarn codegen # Generate native bindings + docs from source
yarn prepack # Build library to /lib/Critical: Never edit generated files (they have header comments). Edit source, then yarn codegen.
Example apps use source files directly - TypeScript changes hot reload, native changes need rebuild.
React Native App (preferred):
yarn examples:react-native ios:pod-install # iOS only, first time or Podfile changes
yarn examples:react-native start # Metro bundler
yarn examples:react-native android # Build/run Android
yarn examples:react-native ios # Build/run iOS
yarn examples:react-native purge # Clean build artifactsExpo App:
yarn examples:expo android/ios/start
yarn examples:expo purgeNative code changes: Rebuild via IDE (Xcode/Android Studio) or CLI commands above.
TypeScript: Open repo root in VSCode/WebStorm (configure yarn 4 editor SDKs)
Android: Open /examples/react-native-app/android in Android Studio (library = mlrn module)
iOS: Open /examples/react-native-app/ios/MapLibreReactNativeExample.xcworkspace in Xcode (library under Pods > Development Pods)
Located in /examples/react-native-app/e2e/. Tests run in CI on every PR.
# Build and run the React Native example app on emulator/simulator
yarn examples:react-native android # or ios
# Run tests
maestro test ./examples/react-native-app/e2e/tests- Tests produce JUnit XML reports at
examples/react-native-app/report.xml
/
├── src/ # Main TypeScript source
│ ├── index.ts # Main library export
│ ├── components/ # React components (MapView, Camera, etc.)
│ ├── modules/ # Native modules
│ ├── types/ # TypeScript type definitions
│ ├── utils/ # Utility functions
│ ├── plugin/ # Expo config plugin
│ └── __tests__/ # Jest unit tests
├── android/ # Android native code
│ ├── src/main/java/org/maplibre/reactnative/
│ ├── build.gradle # Android build config
│ └── gradle.properties # Native version config
├── ios/ # iOS native code
│ ├── components/ # Native view managers
│ ├── modules/ # Native modules
│ └── utils/ # Objective-C utilities
├── scripts/ # Build and codegen scripts
│ ├── codegen.ts # Main codegen script
│ └── templates/ # EJS templates for codegen
├── examples/
│ ├── shared/ # Shared example scenes
│ ├── react-native-app/ # RN example (new arch)
│ │ ├── android/
│ │ ├── ios/
│ │ └── e2e/ # Maestro E2E tests
│ └── expo-app/ # Expo example
├── docs/ # Docusaurus documentation site
├── .github/
│ ├── workflows/ # CI/CD pipelines
│ │ ├── review.yml # Main PR checks
│ │ ├── release.yml # Semantic release
│ │ ├── review-android.yml # Android build & test
│ │ └── review-ios.yml # iOS build & test
│ └── actions/setup/ # Shared setup action
├── package.json # Main package config
├── tsconfig.json # TypeScript config (strict mode)
├── tsconfig.build.json # Build-specific TS config
├── jest.config.ts # Jest test config
├── .eslintrc.js # ESLint config (universe/native)
├── babel.config.js # Babel config
├── MapLibreReactNative.podspec # iOS podspec
└── .nvmrc # Node version (24.11.0)
All checks must pass before merge:
- lint-tsc: TypeScript type checking (
yarn lint:tsc) - lint-eslint: ESLint with 0 warnings (
yarn lint:eslint) - test: Jest unit tests (
yarn test) - codegen: Verify codegen runs without changes (
yarn codegen) - build-library: Build library package (
yarn prepack) - review-android: Build Android app + Maestro E2E tests
- review-ios: Build iOS app + Maestro E2E tests
- Uses semantic-release based on conventional commits
- Runs on push to
main,beta, oralphabranches - Automatically updates CHANGELOG.md, package version, and publishes to npm
- IMPORTANT: PR titles must follow Conventional Commits format
Solution: Always run yarn prepack after yarn codegen to rebuild type declarations.
Solution:
yarn examples:react-native purge:ios
yarn install
yarn examples:react-native iosSolution:
yarn examples:react-native purge:android
yarn install
yarn examples:react-native androidSolution:
yarn examples:react-native purge:js
yarn install
yarn examples:react-native start --reset-cache- TypeScript changes: Should hot reload automatically
- Native changes: Rebuild the native app
- Dependency changes: Run
yarn installand rebuild
- Use conventional commits: PR titles and commits must follow format (feat:, fix:, chore:, etc.)
- Always run TypeScript linters before committing, when
.tsor.tsxfiles changed:yarn lint - Add tests for new features: Unit tests in
/src/__tests__/ - Add example scenes: Demonstrate features in
/examples/shared/src/examples/ - Document with TSDoc: Use TSDoc comments for components/modules (feeds codegen)
- Never edit generated files: Edit templates in
/scripts/templates/instead - Test on both platforms: Verify changes work on Android and iOS
- Keep PR scope focused: Small, atomic changes are easier to review
- tsconfig.json: Strict mode, bundler module resolution, path aliases for
@maplibre/maplibre-react-native - .eslintrc.js: Extends universe/native, 0 warnings enforced
- jest.config.ts: React Native preset, mocks in
src/__tests__/__mocks__/, path aliases viamoduleNameMapper - package.json:
codegenConfigfor React Native new arch - .clang-format: Google style, 120 column limit for Objective-C
- MapLibreReactNative.podspec: iOS native version config
- android/gradle.properties: Android native version config
- examples/shared/babel.shared.js: Babel module resolver for
@alias - examples/shared/metro.shared.js: Metro extraNodeModules for
@alias - examples/shared/tsconfig.json: TypeScript paths for
@/*alias
These instructions have been compiled from repository documentation, configuration files, and CI workflows. Trust this information and only search the codebase if you need specific implementation details not covered here or encounter errors suggesting these instructions are outdated.