CLI tool
margelo/react-native-blurhash avatar
margelo/react-native-blurhash

react-native-blurhash: decoding image placeholders on the native thread

🖼️ A library to show colorful blurry placeholders while your content loads.

2,240 stars89 forksKotlinMIT

At a glance

What is it?
A React Native UI module that renders a BlurHash string as a blurry image while the real one downloads, with an encoder, async decoding, and performance knobs for long lists.
Who is it for?
The idea this library implements is small and the execution is careful: a BlurHash string is a few dozen characters of average colour and a low frequency image component, so you can store it in your database next to the post, ship it with the feed, and paint a recognisable blur before the full image arrives. That is a better loading experience than a grey box and a much better payload than a thumbnail.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly Kotlin, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 7, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What a BlurHash actually is

The README describes BlurHash as a compact representation of a placeholder for an image, and the alternative it names is boring grey little boxes. The mechanics are worth understanding because they explain the prop list. A BlurHash encodes average colour plus a handful of low frequency components of the image in a short base83-ish string, so decoding it is a few dozen multiply-add operations rather than a JPEG decode. That is why it can run cheaply on the UI thread for every cell in a list, and why `decodeWidth` and `decodeHeight` are resolution parameters rather than resize hints.

The algorithm is not this repository's work. The README credits woltapp/blurhash as the creator of the algorithm and links to that repository for an algorithm explanation, and the example workflow links to the C encoder there. What this repository adds is the React Native binding, on iOS and Android, plus an encoder so you can produce hashes from inside the app rather than only on a server.

The sample hash the README uses in the prop table is `LGFFaXYk^6#M@-5c,1J5@[or[Q6`, and blurha.sh is offered as the place to generate example strings interactively.

Install is npm plus pod install

Two commands, because there is native code on both sides.

bash
npm i react-native-blurhash
npx pod-install

The package is `react-native-blurhash` at version 2.1.3, MIT licensed, authored by Marc Rousavy. It is built with `bob build` and published with `release-it`, and the published `files` list in `package.json` is unusually precise about what ships: the Android sources and gradle files, the iOS project and its headers and Swift and Objective-C sources, the `lib/commonjs`, `lib/module` and `lib/typescript` outputs, the `src` directory, and the podspec. That is the shape of a proper native module rather than a shim.

The Expo section is the part that saves people an afternoon. The library works with Development Builds and no config plugin is required, and it cannot be used in Expo Go because it requires custom native code. That is the expected behaviour for any module with an Android and iOS implementation, and the README says so directly instead of leaving you to discover it from a red screen.

The props that matter are decode size and threading

The prop table is long, but only four entries carry a real design decision. `decodeWidth` and `decodeHeight` set the resolution to decode to, default to 32, and the README's guidance is direct: use 16 for large lists, otherwise you can increase it to 32. Higher values decrease performance. Since a BlurHash is a smooth blur, decoding it at a tiny resolution loses almost nothing visually, and doing so is what keeps a scrolling feed smooth.

`decodeAsync` defaults to false and switches decoding onto a background thread instead of the UI thread. For a list you should turn it on; for a single hero image on a screen with nothing else happening, the default is fine and avoids a thread hop.

`decodePunch` adjusts the contrast of the output image, defaulting to 1.0, and the README's phrasing is that you tweak it if you want a different look for your placeholders. It is a blunt instrument with one job, which is exactly what you want for consistency across a feed.

`resizeMode` accepts cover, contain, stretch or center, and the README notes that repeat is not supported, because it maps to `Image::resizeMode` rather than being implemented fresh. All React Native `View` props pass through, with `style.width` and `style.height` for display size and a note that `style.borderRadius` is natively supported on iOS.

The workflow the README recommends: encode on the server

The example workflow section is the most opinionated part of the README, and it argues for encoding server-side. A user creates a post, the server function receives an image payload plus post data, and then the server generates a blurhash from the image using the C encoder, stores the post data including the generated blurhash string in the database, and uploads the image to a CDN.

The payoff is described next: every time a feed loads, you can immediately show a BlurHash component with the post's `.blurhash` property over your `Image`, and fade it out once the `Image` component's `onLoadEnd` has been called.

That ordering is the whole design. The hash arrives in the feed payload as ordinary data, so the placeholder costs nothing extra to fetch, and the fade is driven by a callback you already have. A blockquote in the same section notes you can also use the react-native-blurhash encoder to encode straight from your React Native app, which is the escape hatch for when the image never goes through your server, such as a photo picked from the device library.

The component reflects that with its callback trio: `onLoadStart` when decoding begins, `onLoadEnd` when the hash has decoded and rendered to the view, and `onLoadError` with an optional message parameter when it fails.

Signals from the repository, and one thing to check

GitHub reports Kotlin as the primary language, which tells you the Android side carries most of the recent work, and the tree has `android/` and `ios/` directories alongside `src/`, `example/`, a `.clang-format` for the native sources, a `tea.yaml`, a podspec, and both `tsconfig.json` and `tsconfig.build.json`. There is a `CONTRIBUTING.md` and a `hacktoberfest` topic. Scale is 2239 stars, 89 forks, 33 open issues, not archived, MIT licensed, with releases in February, August and December 2025 and a last push on 2026-03-19.

The thing to check is the peer dependency range. `package.json` declares `react-native` as `>=0.60.0-rc.0 <1.0.x`, which describes React Native 0.60 through 0.x and stops before 1.0. React Native has been well past 1.0 for a while, so a range that excludes every current release is worth raising as an issue rather than assuming. The upper bound is conservative rather than wrong, since the library's use of the legacy native module bridge has not obviously changed, but it does mean your package manager will surface a peer warning that only you can judge.

One more small inconsistency: the repository is hosted under margelo while `package.json` and the README's image links point at mrousavy, the author's own account. Both work, and it reflects a change of organisation rather than a mistake.

Editorial conclusion

The idea this library implements is small and the execution is careful: a BlurHash string is a few dozen characters of average colour and a low frequency image component, so you can store it in your database next to the post, ship it with the feed, and paint a recognisable blur before the full image arrives. That is a better loading experience than a grey box and a much better payload than a thumbnail. What the component gives you beyond the algorithm is the native path on both platforms, asynchronous decoding off the UI thread, and explicit guidance that decode sizes of 16 are for long lists while 32 is for everything else. The catch is scope: this is a placeholder renderer, not an image component, so you still hand loading and caching to `Image` and use `onLoadEnd` to fade the blur out. Install from npm and run `npx pod-install`.

Frequently asked questions

What does a BlurHash string look like and how long is it?

The README's example is `LGFFaXYk^6#M@-5c,1J5@[or[Q6`, which is short enough to store in a database column next to your post and send in a feed response. It encodes average colour plus a few low frequency image components, so decoding it costs far less than decoding a real image. blurha.sh generates example strings interactively.

Can I use react-native-blurhash with Expo?

Yes with Development Builds, and no with Expo Go. The README states you can use it with Development Builds with no config plugin required, but that it cannot be used in the Expo Go app because it requires custom native code. That is the normal limitation of any module with an iOS and Android implementation.

Which decode size should I use for a long list?

Use 16 for both `decodeWidth` and `decodeHeight` in a large list, and 32 otherwise. The README is explicit that higher values decrease performance, and the defaults are 32. A BlurHash is a smooth blur, so dropping the decode resolution costs very little visually and keeps scrolling smooth. Turn on `decodeAsync` in a list as well, so decoding happens on a background thread.

Should I encode the BlurHash on the server or in the app?

The README's example workflow does it on the server, generating the hash from the image payload with the C encoder, storing it in the database with the post, and uploading the image to a CDN. That way the hash arrives with the feed and the placeholder costs nothing extra. The component also ships an encoder, so you can encode from the app when the image never touches your server.

How do I fade the placeholder out when the image loads?

Render the BlurHash component over your `Image`, then trigger your fade from the `Image` component's `onLoadEnd`. The BlurHash component exposes its own `onLoadStart`, `onLoadEnd` and `onLoadError` callbacks for when the hash itself decodes or fails, which are separate from the full image loading.

Official sources

  1. License: MIT
  2. margelo/react-native-blurhash on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/margelo-react-native-blurhash.svg)](https://hysenlabs.com/projects/margelo-react-native-blurhash)