React Native and Expo images from Supabase Storage

The @prodkit-cloud/react-native package provides a native Image wrapper and a pure source builder for Expo and bare React Native apps. It applies device pixel density before requesting optimized variants.

SDK coming soon

@prodkit-cloud/react-native isn't published yet, so the guides below skip the install step. Until it is, build image URLs from your endpoint with URL parameters. They work in any React Native app with no package:

URL API

import { Image, PixelRatio } from "react-native"

export function Avatar() {
  const width = PixelRatio.getPixelSizeForLayoutSize(128)

  return (
    <Image
      source={{ uri: `https://img.prodkit.cloud/acme/avatars/cory.png?width=${width}` }}
      style={{ width: 128, height: 128 }}
      accessibilityLabel="Avatar"
    />
  )
}

Render a native image

Use the wrapper anywhere you would use React Native's Image. Native props and refs are forwarded.

Example

import { Image } from "@prodkit-cloud/react-native"

<Image
  project="acme"
  src="avatars/cory.png"
  width={128}
  height={128}
  style={{ width: 128, height: 128 }}
  accessibilityLabel="Avatar"
/>

Crop to faces

gravity="face" keeps faces in frame when the image is cropped to the requested size.

Example

<Image
  project="acme"
  src="avatars/cory.png"
  width={96}
  height={96}
  gravity="face"
  style={{ width: 96, height: 96, borderRadius: 48 }}
/>

Build a source object

For custom image components, build a React Native source object directly. Pass scale explicitly in tests or non-device environments.

Example

import { buildImageSource } from "@prodkit-cloud/react-native"

const source = buildImageSource("covers/launch.jpg", {
  project: "acme",
  width: 320,
  height: 180,
  scale: 3,
})

Test with Jest

The package ships as ESM, and the React Native Jest preset only transforms React Native's own packages. Add @prodkit-cloud to the pattern so tests that render Image can import it. With jest-expo, add @prodkit-cloud to its documented pattern instead.

Example

// jest.config.js
module.exports = {
  preset: "react-native",
  transformIgnorePatterns: [
    "node_modules/(?!(?:.pnpm/)?((jest-)?react-native|@react-native(-community)?|@prodkit-cloud))",
  ],
}

Native Image props

Image accepts src or source as a string, ProdKit transform props, and forwards native Image props. buildImageSource is available for custom native image primitives.

NameDescriptionValuesDefault
srcImage path within your project, or a full Supabase Storage URL to rewrite.stringRequired
widthDisplay width in density-independent pixels. The wrapper applies PixelRatio to the requested variant.1-4096Original width
heightDisplay height in density-independent pixels. The wrapper applies PixelRatio to the requested variant.1-4096Original height
scaleExplicit pixel scale for buildImageSource. The Image wrapper uses PixelRatio.get().numberDevice pixel ratio
projectProject slug from the dashboard. Can be passed through ProdKitProvider.stringRequired
imageBaseUrlCustom image service base URL for self-hosted or preview environments.absolute URLhttps://img.prodkit.cloud
qualityCompression quality, rounded to the nearest of 30, 40, 50, 60, 70, 75, 80, 82, 85, 90, 95, or 100. q works as a short alias.1-10082
fitHow the image fills the requested dimensions.scale-down, contain, cover, crop, padscale-down
formatOutput format. auto negotiates AVIF or WebP from the Accept header.auto, avif, webp, jpeg, pngauto
dprDevice pixel ratio for high-density screens. Multiplies width and height before rounding.1-31
gravityWhere cover and crop fits keep the image: face (detected faces), auto (the most interesting region), a side, or a focal point XxY from 0 to 1. Sets fit=cover unless you choose a fit."auto", "face", "top", "bottom", "left", "right", { x, y }Center
zoomWith gravity=face, how tightly to crop around faces, from 0 (loose) to 1 (tight).0-1None
blurBlur radius, rounded to a standard level. With a small width, makes a lightweight placeholder.1-250None
sharpenSharpening strength. 1 suits most downscaled images.0-10None
removeBackgroundCuts out the subject with a transparent background (beta).booleanfalse