Skip to main content

Re.Pack Setup

This guide covers setting up Storybook with Re.Pack projects that use Rspack or Webpack instead of Metro as the bundler.

For a ready-to-go starter project, check out the RepackStorybookStarter repository.

Installation

Use the Storybook CLI to initialize your project:

npm create storybook -- --type react_native --yes

Install Reanimated and Worklets

Storybook's default UI requires react-native-reanimated and react-native-worklets:

npm install react-native-reanimated react-native-worklets

Then ensure the worklets babel plugin is in babel.config.js. It must be the last plugin in the list:

// babel.config.js
module.exports = {
presets: [
// your existing preset, e.g.:
'module:@react-native/babel-preset',
],
plugins: [
// ... any other plugins
'react-native-worklets/plugin', // must be last
],
};

Configure Rspack/Webpack

Instead of wrapping Metro with withStorybook, add the StorybookPlugin to your rspack/webpack config plugins array.

Use an environment variable (STORYBOOK_ENABLED) to control both the plugin behavior and a build-time constant for your app code:

// rspack.config.mjs
import * as Repack from '@callstack/repack';
import rspack from '@rspack/core';
import { StorybookPlugin } from '@storybook/react-native/repack/withStorybook';

const storybookEnabled = process.env.STORYBOOK_ENABLED === 'true';

export default Repack.defineRspackConfig({
// ... your existing config
resolve: {
...Repack.getResolveOptions({
enablePackageExports: true, // required for storybook package resolution
}),
},
plugins: [
new Repack.RepackPlugin(),
new rspack.DefinePlugin({
STORYBOOK_ENABLED: JSON.stringify(storybookEnabled),
}),
new StorybookPlugin({
enabled: storybookEnabled,
websockets: 'auto',
}),
// ... your other plugins
],
});
Important

enablePackageExports: true is required so rspack can correctly resolve Storybook's package exports (e.g. @storybook/react-native/preview). Without it, imports from Storybook packages will fail.

info

Unlike the Metro setup, there is no need to configure require.context support — rspack handles it natively.

Create Entrypoint

Conditionally render Storybook based on the STORYBOOK_ENABLED build-time constant. Since StorybookPlugin replaces Storybook imports with empty modules when disabled, you can import Storybook at the top level safely:

// App.tsx
import StorybookUI from './.rnstorybook';

declare const STORYBOOK_ENABLED: boolean;

export default function App() {
if (STORYBOOK_ENABLED) {
return <StorybookUI />;
}

// Your existing app code here
return (
// ...
);
}

The declare const tells TypeScript about the global that rspack's DefinePlugin injects. When STORYBOOK_ENABLED is false, rspack dead-code-eliminates the Storybook branch entirely.

Add Scripts

{
"scripts": {
"storybook": "STORYBOOK_ENABLED='true' react-native start",
"storybook:ios": "STORYBOOK_ENABLED='true' react-native run-ios",
"storybook:android": "STORYBOOK_ENABLED='true' react-native run-android"
}
}

Replace react-native with rock if your project uses Rock CLI.

Run

npm run storybook

StorybookPlugin Options

OptionTypeDefaultDescription
enabledbooleantrueStrip Storybook from bundle when false
configPathstring'./.rnstorybook'Storybook config directory
useJsbooleanfalseGenerate .js instead of .ts
docToolsbooleantrueAuto arg extraction
liteModebooleanfalseMock default UI deps (use with @storybook/react-native-ui-lite)
websockets'auto' | objectundefined'auto' detects LAN IP, or { port: 7007, host: 'localhost' }