I Finally Migrated from NativeBase to Gluestack-UI

I finally ripped native-base out of our production app last night. We’ve been maintaining this massive 150-screen monster since 2021, and the technical debt was starting to physically hurt.

If you’ve been working in React Native for the past few years, you already know the story. NativeBase v3 was incredibly popular when it dropped. It gave us a beautiful utility-first API. But as our app grew, the performance issues became impossible to ignore. The React context re-renders were brutal on low-end Android devices. The creators knew it too, which is exactly why they built gluestack-ui to replace it.

But management is never going to approve a three-month UI rewrite just because developers are complaining about frame drops. We needed a bridge.

Testing the Migration Adapter

Enter the @gluestack-ui/themed-native-base migration library. I’ve been watching this thing move through its alpha and beta phases, and I finally decided to be the guinea pig for our staging environment.

Well, that’s not entirely accurate — I’ll be honest. I expected a complete disaster. Drop-in replacements for complex UI frameworks usually are. You swap a dependency, and suddenly half your buttons are rendering off-screen.

I ran this on my M2 MacBook Pro running Sonoma 14.2, against a codebase stuck on React Native 0.73.4 and NativeBase 3.4.28. The actual mechanical swap is pretty clever. You don’t go through and change thousands of import statements. Instead, you hijack the imports at the bundler level.

React Native programming - The complete guide to React Native for Web - LogRocket Blog
React Native programming – The complete guide to React Native for Web – LogRocket Blog

You just drop this into your Babel config:

module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: [
      [
        'module-resolver',
        {
          alias: {
            'native-base': '@gluestack-ui/themed-native-base',
          },
        },
      ],
    ],
  };
};

The initial reload was weirdly quiet. Most of our basic layout components—the Box, VStack, and HStack instances we had plastered everywhere—just worked. No red screens. No exploded layouts. The visual regression tests actually passed for about 80% of our screens on the first try.

The Hook Nightmare

Then I hit the custom hooks. This is where the adapter stops holding your hand.

But generally, if your app heavily relies on useTheme or useToken to pull specific design tokens into non-UI components (like passing theme colors to a third-party charting library), you are going to spend some time refactoring.

The adapter does a great job translating the JSX props, but the underlying theme object structure in gluestack is fundamentally different. NativeBase nested things in a way that gluestack flattens out.

Here is a specific gotcha that burned two hours of my life. If you had custom font weights mapped in your old NativeBase theme config, the adapter occasionally resolves them as undefined if you try to pull them via hooks without explicit string casting. All my bold text suddenly looked like regular weight on Android, but only inside components where I was manually passing the style prop instead of using the utility props.

I had to rewrite several of our custom wrappers to stop relying on the old hook patterns and instead use the new gluestack token resolver:

// The old way that broke silently
import { useToken } from 'native-base';

const MyChart = () => {
  const [primaryColor] = useToken('colors', ['primary.500']);
  return <LineChart color={primaryColor} />;
}

// The fix using the adapter's expected format
import { useToken } from '@gluestack-ui/themed-native-base';

const MyChart = () => {
  // You have to be much more explicit with the token paths now
  const primaryColor = useToken('colors', 'primary500'); 
  return <LineChart color={primaryColor} />;
}

Real Performance Numbers

I didn’t just do this to use newer syntax. I wanted my frames back.

And I profiled the app before and after the swap using React Native Debugger. Our old NativeBase setup was causing massive render delays on a heavily nested feed view. We were seeing 45-50ms render times per item when scrolling fast.

After swapping to the themed gluestack adapter, that dropped to about 18ms. We also cut our initial JS bundle size by roughly 14%.

Is it the pure, unadulterated performance of raw gluestack-ui v2? Probably not. You’re still carrying some adapter overhead. If you want absolute bare-metal performance, you should be looking at Tamagui or building your own components with Nativewind. But for a find-and-replace migration that I finished over a weekend? I’ll take that performance bump every single time.

What Happens Next

Look, don’t treat this adapter as your forever home. It’s a temporary bridge to get you off a deprecated library without halting your product roadmap.

My plan is pretty straightforward. I’m using this adapter to stop the bleeding today. It gets us onto a maintained dependency tree and fixes the worst of our performance bottlenecks. But by Q1 2027, my goal is to incrementally replace the aliased imports with pure gluestack-ui components, one feature branch at a time.

And if you’ve been dreading this migration and putting it off, just do it. The tooling is finally stable enough to handle complex production apps. Just keep a close eye on your typography tokens and be ready to rewrite a few custom hooks. It beats rewriting the whole app.

Frequently asked questions

How do I migrate from NativeBase to gluestack-ui without changing every import?

You can use the @gluestack-ui/themed-native-base adapter and alias imports at the bundler level instead of editing thousands of files. Add the module-resolver plugin to your Babel config to map ‘native-base’ to ‘@gluestack-ui/themed-native-base’. After reload, basic layout components like Box, VStack, and HStack generally work immediately, with roughly 80% of screens passing visual regression on the first try.

Why is useToken returning undefined after switching to the gluestack-ui adapter?

The adapter translates JSX props well, but the underlying theme object in gluestack is flattened compared to NativeBase’s nested structure. Custom font weights pulled via hooks can resolve as undefined without explicit string casting, causing bold text to render as regular weight on Android. The fix is importing useToken from ‘@gluestack-ui/themed-native-base’ and using explicit flattened token paths like ‘primary500’ instead of ‘primary.500’.

What performance improvement does the gluestack-ui themed-native-base adapter actually deliver?

Profiling a heavily nested feed view with React Native Debugger showed render times dropping from 45-50ms per item during fast scrolling down to about 18ms after the swap. The initial JavaScript bundle size also shrank by roughly 14%. This isn’t as fast as raw gluestack-ui v2 since adapter overhead remains, but it’s a significant gain for a weekend find-and-replace migration.

Should I use the gluestack-ui adapter long-term or move to Tamagui or Nativewind?

The adapter is a temporary bridge, not a forever home. Use it to stop the bleeding, escape the deprecated NativeBase dependency, and fix the worst performance bottlenecks today. For absolute bare-metal performance, Tamagui or custom components built with Nativewind are better options. A practical plan is incrementally replacing aliased imports with pure gluestack-ui components feature-by-feature, targeting completion by Q1 2027.

Leave a Reply

Your email address will not be published. Required fields are marked *