react-native-gzip
Native gzip compression and decompression for React Native, using platform-native zlib on iOS and Android.
Repository Health
Technical Analysis
react-native-gzip is a small native module that brings gzip compression to React Native apps by wrapping each platform’s built-in zlib implementation — java.util.zip.GZIPOutputStream/GZIPInputStream on Android and the GZIP CocoaPod (backed by Apple’s libz) on iOS. Rather than shipping a JavaScript gzip implementation that runs on the JS thread, it delegates the actual compression work to native code and exposes just two async functions, deflate and inflate, that take and return base64-encoded strings.
The library is intentionally minimal: no native module configuration, no bridging beyond the default RCTBridgeModule/TurboModule setup, and support for both the old and new React Native architectures via a conditional TurboModule spec (RNGzipSpec). It’s most useful for apps that need to shrink payloads before writing them to storage, sending them over a low-bandwidth connection, or persisting large JSON blobs locally without paying the JS-thread cost of a pure-JS compression library.
What You Get
- Native gzip compression via Android’s java.util.zip.GZIPOutputStream and iOS’s GZIP CocoaPod (libz)
- Two-function API — deflate(string) and inflate(base64) — both returning promises
- Base64 in, base64 out — output is ready to store in JSON or send over the wire without extra encoding steps
- Old and new React Native architecture support via a conditional TurboModule (RNGzipSpec) code path
Common Use Cases
- Compressing large JSON payloads before caching them in AsyncStorage or MMKV
- Shrinking request bodies before sending them to a backend over a slow mobile connection
- Decompressing gzip-encoded API responses on-device without pulling in a JS zlib port
- Reducing the size of offline-sync payloads in apps that batch data for later upload
Under The Hood
Architecture react-native-gzip follows the standard React Native native-module architecture: a single JS entry point (src/index.tsx) that resolves NativeModules.Gzip (falling back to a Proxy that throws a linking error) and exposes two thin wrapper functions, inflate and deflate, which simply forward to the native module and return its promise. On Android, GzipModule.java (a ReactContextBaseJavaModule) implements the two @ReactMethod handlers directly against java.util.zip.GZIPOutputStream/GZIPInputStream, with GzipPackage.java registering the module. On iOS, Gzip.mm implements the equivalent RCT_REMAP_METHOD handlers using the NSData+GZIP and MF_Base64Additions CocoaPods, and Gzip.h conditionally implements either the legacy RCTBridgeModule protocol or, when RCT_NEW_ARCH_ENABLED is set, the codegen’d NativeGzipSpec TurboModule protocol via getTurboModule. There is no shared abstraction layer, no configuration surface, and no intermediate C++/JSI code — the JS layer is a pass-through and each platform’s compression logic lives entirely in its own native file, so changing behavior on one platform requires touching that platform’s file only.
Tech Stack The package is a bare React Native library scaffolded with create-react-native-library/react-native-builder-bob (bob build compiles src/ to lib/commonjs, lib/module, and lib/typescript via tsconfig.build.json). The JS/TS surface is minimal, with react and react-native declared only as peer dependencies. Android uses standard React Native bridge APIs (ReactContextBaseJavaModule, @ReactModule) plus the JDK’s built-in java.util.zip — no third-party Android dependency for compression itself. iOS pulls in two CocoaPods declared in react-native-gzip.podspec: GZIP (a thin wrapper around Apple’s libz) and Base64, and the podspec conditionally adds React-Codegen/RCT-Folly/RCTRequired/RCTTypeSafety/ReactCommon dependencies when RCT_NEW_ARCH_ENABLED=1 for the new architecture’s Folly/JSI-based build. Tooling follows the typical bob/lefthook/commitlint/release-it/ESLint+Prettier stack seen in create-react-native-library-generated packages, with CircleCI configured for CI.
Code Quality Test coverage is effectively nonexistent: the only test file, src/tests/index.test.tsx, contains a single it.todo(‘write a test’) placeholder — there is no assertion anywhere in the repository for either the JS wrapper or the native implementations, and no Android/iOS unit tests either. Error handling is present but shallow: the Android module wraps its zip operations in try/catch and rejects the promise with a generic ERROR_FAILED code and the raw exception, while the iOS implementation performs no error handling at all — a malformed base64 string or non-UTF8 decompressed output would throw or produce undefined behavior rather than a rejected promise. Naming is conventional and consistent (deflate/inflate mirroring Node’s zlib naming), and TypeScript types are declared for the two exported functions, with ESLint (@react-native-community config) and Prettier configured — but there’s limited signal that CI enforces either against changes, and the project has had no commits since its last release.
API Design The public API is intentionally tiny — two functions, deflate(string) => Promise<string> and inflate(base64) => Promise<string> — with no configuration options, compression-level parameters, or streaming support, which makes it trivial to adopt (import, call, await) but inflexible for anything beyond simple whole-string compression. It doesn’t wrap or extend an external SaaS/API surface, and its only distinguishing value over a JS-based compression library is offloading the work to native platform code instead of running on the JS thread — useful for larger payloads on lower-end Android devices. Documentation is limited to a short README code sample, with no discussion of buffer size, error codes, or maximum input size, so a consumer has to read the native source to understand failure modes.