NH
By
Nahuel Alberti
,
Head of Engineering
Share
Copied!
May 8, 2025
10 min read

The Universal Way: One Codebase, all platforms

NH
By
Nahuel Alberti
,
Head of Engineering

Write Once, Run Anywhere is a dream since the 90s, a continuous quest that evolved over the years. Today, thanks to the maturation of certain technologies, we can seriously speak of its natural evolution: **Write Once, Compile Anywhere**.

Historically, engineers have a kind of functional laziness: we seek to optimize, abstract and standardize everything repetitive in order to focus on what **really matters**. A pursuit that improves our lives and often positively impacts our teams, our organization, the community and even the industry.

The engineer's world is built on layers of abstraction, some good, some bad... but all born out of the constant desire to optimize our productivity and have more impact with less effort.

Back in 2019 a project came to Paisanos that needed to add new functionalities and renew its product. At Paisanos we already had experience transforming obsolete and slow products into memorable and impactful experiences. I remember that the client constantly mentioned “compatibility” and “consistency” problems, something that can happen when interacting with old technologies or bad practices.
In reviewing the platform we found a mix of Electron, React, React Native, React Native Web, and lots and lots of workarounds, all under react-native-web. They had tried to build a universal app but the result was bad, they had a lot of problems sharing code between platforms.

The end result: they reworked everything in separate projects, leaving behind the idea of something universal.

Conceptually the idea was great: a single codebase, multiple platforms... but that spectacular concept was overshadowed by the impossibility of being executed effectively, at some point because there was not the necessary progress to achieve the expected result effectively.

In our environment, everything is a matter of timing and technological advancement, many concepts are good in theory, but if we do not have the technology, we tend to keep it in a drawer until the world is ready or we do something about it to make it a reality.

Today, the time is now. The tools have matured. Building truly cross-platform products that are fast, consistent and scalable is a real possibility.

In these years we have tested dozens of technologies, launched products for startups and large companies, and learned a lot. Here are a couple of lessons we have learned after deploying several universal applications and reaching +2M users and a +4.5 average rating in the stores.

Why a Universal App?

Digital products are, for the most part, channels to connect people with the value proposition of our product. The more presence we have, the more users we can reach, so the more opportunities for us to succeed.
A universal app allows you to be on all devices with a single technical effort.

- Mobile is still the king of engagement and activation: notifications, proximity to the hardware, more focused experience and direct access at a tap away.
- Web remains unbeatable in acquisition: they can find our product with a simple Google search (or some AI), they can share a URL and reach us faster.

In addition, a universal application can not only increase our presence, but also optimize our team.
Where before there was the need to manage three different teams (iOS, Android, Web), today a single team can manage everything using a single code base. This means that fewer or the same amount of people can do more and focus on functionality, discovery and simply be better professionally.
In our experience, building universal applications reduced the need for a team by 30-40%, and where there was no reduction, there was a considerable increase in the speed of delivery and discovery.

Universal = more brand presence and less operational cost or impact per build cycle.


It wasn't always the best choice

I'm an early adapter by nature, which gives me the opportunity to continually validate technology and experiment, choosing what can benefit the team today and what has future potential. But this mindset, poorly controlled, can be detrimental if you adopt something too early in a product that has to scale.
At Paisanos we build many products, some universal apps: fintech, entertainment, sports.
Several years ago, one of these products was an entertainment product whose need was aimed directly at being a Universal App, it needed to be present in all possible devices, the features and UI were going to be the same, and they had a very tight budget.

I remember that my enthusiasm was incredible, since it was the opportunity to implement Universals after so many months testing in the Paisanos LAB, a place where we do controlled tests and see what we should or should not adopt. So, after a period of architecture, we decided to go full Universal.

For that product, we used Expo to create an app in React Native and use the export web feature as a SPA. Expo was just starting at that time and both documentation, guides and libraries were a bit early.

The first months went quite well, but as time went by we encountered several problems: Some mobile <> web compatibility in libraries, which meant opting for community libraries or directly building/adapting some ourselves, we found ourselves making many platform specific files (.ios.tsx, .web.tsx), and using a lot of lazy loading/code splitting because the SPA bundle was too heavy on Web and killed us Core Web Vitals and not to mention SEO....

It was a product where we gained a lot of development time and were able to test Universals at scale, we also faced a lot of unnecessary technical complexities, but those are the tradeoffs of any architecture decision. Still, the product was successful, got investment and left us with a lot of learnings.

Now, it is possible

A few years ago Solito came out, a library created by Nando Rojo, an engineer who is very involved in the react native open source community, gives us two great things (extracted from his website):

- A wrapper to share navigation between React Native (or Expo) and Nextjs.
- A set of patterns and example to build cross platform applications with React Native and Nextjs.

By the end of 2023 we will be able to start building a universal app for Boca Juniors, an Argentinean soccer club. The need, the opportunity and the technological advancement gave us the chance to really consolidate the years of learning into an amazing universal product.
After having extensively analyzed the architecture and deciding which way to go, we understood that the only risk we had to any blocking of this approach could be solved by making separate components without affecting other features or simply ejecting the application, since being a monorepo, at its core they are separate applications.

Boca is a piece of technology that really squeezed the possibilities of Nextjs and Expo into its union and its division. As a web application, the product requires a lot of flexibility in terms of rendering patterns, integrations and security. In mobile there are certain particularities that are also important: in some flows it takes a hybrid approach, relying heavily on Nextjs, others purely native relying on Expo, with various vendor integrations and custom modules.
Despite this, in the mobile application you never feel the change from when something is running native or with an embedded web, something that can only be achieved thanks to the union of both technologies.

This choice allowed us to build a scalable, secure product that hosts hundreds of thousands of users with an extremely high traffic of moments, without failures, without problems and with a team that does not need to maintain two (or three) platforms at the same time.

Structurally Solito poses a mono repository architecture, where you have two major artifacts:

- Apps: Where your separate applications live, basically you can start with one in expo and next, but you can add as many as you want: storybook, desktop, you choose. This approach allows that although you share code, you can make more customized decisions for each specific framework.
- Packages: Here live the packages that are shared between the different applications, roughly speaking they can be ui components, whole features and your lib with business logic, utils, etc.

Large enterprise applications tend to need to squeeze the most out of whatever framework you are using, being locked into something that is in beta or experimental can be a pretty serious problem if you don't have a backup plan. That's where Solito shines, you're always in separate applications, but sharing logic and components.

But today, in 2025, Solito is not the only way


Expo is doing an amazing job in finally giving React Native a robust ecosystem. Just a few years ago, mobile development with RN depended almost entirely on community effort. Today, Expo has become the default for building mobile apps with React Native.

With the release of its version 52, Expo introduces a stable Expo Router, which allows you to build universal apps without having to manage multiple separate projects. The build is optimized for both Web and Mobile, and the use of file-based routing brings it very close to the Next.js development experience, reducing the learning curve for any web developer.

If you prefer to use Next.js with Expo without going through Solito, you can also follow the official integration guide. Although it is possible, it can get messy if it is not well structured.

Today we are using Expo 52 in universal projects for startups, and the results are excellent. The framework is solid, the development experience is smooth, and there is no doubt: Expo is betting hard to become the new standard for universal application development. And the truth is... it is succeeding.

Be Universal, but with this in mind

The Universal Way can turn into The Universal Mess very quickly and you can have the worst of both worlds: a bad mobile app and a bad web app.
Here are some things you should keep in mind when building one:

Design rules matter

Native mobile apps and responsive web apps don't share the same design rules, each one has its own conventions that, if skipped, can negatively affect the perception of the product.

One of the clearest examples is navigation:

- Using bottom tabs in a web app is confusing or even unnecessary.
- Using a hamburger menu in a native mobile app may seem outdated or go against the patterns expected by users.

Another clear example is manners. While on web they work well in the center of the screen, on mobile it is much more natural to display the component on a bottom sheet.

These are not minor details. They are conventions that when respected reinforce user confidence and when ignored, make the product feel cheap.

That's why your design system and your design and engineering team should work together to define platform-specific components. This differentiation is absolutely necessary if you want your app to feel native wherever it is used.

Lean on existing style libraries

At Paisanos.io we have tested basically all the libraries that exist for Web and Mobile, we love that things look good and that products can be scaled easily (remember css-in-js?).

When you are working with a universal application, there are two great alternatives you can use for styling:

- Tamagui: A universal design system that allows you to build quickly while maintaining visual consistency and high performance on web and mobile. It gives us optimized components for production, themes and a lot of ease in customization and adaptation.
- NativeWind+ RN Reusables: A very web inspired combo, NativeWind allows us to write Tailwind in React Native and RN Reusables gives us many ready-made components in the best Shadcn style. While you will find yourself going more on your own, this combo allows you 100% flexibility if you have to comply with a very particular design system for your product.

At Paisanos we have used both to create products and have had good results. We don't have a favorite, if you come from web maybe NativeWind + RN Reusables can be a combo that generates less learning curve, but Tamagui is simply phenomenal.
What you do remember, is not to go and make universal apps with React Native's Stylesheet, you will find yourself re-inventing the wheel continuously and dealing with a fairly high level of complexity.

Beware of experimental and compatibility

Being an early adopter is great.

If you go into production with something too new, you may pay for it later as bugs or technical debt. If you are going to use it, remember that this decision is a responsibility of you and your team, any inconvenience that arises is not the frameworks fault.

It may not be for you (and that's okay)

Universal applications are great, at startup or side project level you won't have any relevant problems. But at enterprise level, there are a lot of requirements to consider to see if you should go for a universal or not.
Most of the Paisanos products ARE NOT universal, they only happen when the analysis of the architecture as a whole (functional requirements, quality attributes, constraints, context, etc) results in the possibility of making one. The most fundamental thing is not to be hype driven, analyze well what you are going to do before taking this path.
Remember, it can become messy and your universal can be more than a benefit, it can be your downfall, especially at scale.

What is the best option today?

If you are building a universal application, you can go two ways depending on the context and scale of the project:

If it's a side project or a startup, where you know the complexity and scale is going to be manageable, you can go straight with Expo. Their new Expo Router is very powerful and the team behind it is releasing features at an accelerated pace. Keep in mind that many features are still experimental, and on the web you will find some limitations to what Next.js offers in terms of SSR, SEO and capabilities.

If you are developing for a large scale company or product, where you need robustness, flexibility and stability, I recommend using Solito combined with Next.js and Expo. This stack allows you to share components and logic where it makes sense, but also separate specific behaviors or strategies when you need to. It's the best of both worlds: speed and unification without losing control. Enterprise apps often have a high level of specificity, where you need to squeeze your entire stack to meet demanding technical requirements. That adaptability can only be achieved if you have the ability to be universal... but also specific.

In some cases, especially in large companies, it may even be convenient to have separate projects for web and mobile. If so, take that chance. Product credibility is key, and there is nothing worse than the support team having to explain why “the universal app doesn't work”.

From there, you can do what makes the most sense. Technology is a means, not an end, and while the problems may seem similar between products, the contexts almost never are:

- With the acceleration we're seeing thanks to AI, you might even choose to build separate apps and automate the transformation of components across platforms and abstract business logic into shared libraries.
- If you have a solid web built with Next.js, Vue or your framework of choice, you can also use it embedded in a native app. We did it several times as a go-to-market strategy at Paisanos, and it worked very well.

The future of universal apps is magnificent

This last year the battle for Web superiority is finally over and many started to get interested in Mobile and Universal. Competition makes us engineers win and be happy.
Some of the frameworks, technologies or things that are happening in the universal world are:

One Framework: From the creators of Tamagui comes One, a universal framework based on Vite that seeks to create fast applications and become a standard. Although it is not yet ready for production, the team led by [Nate](https://x.com/natebirdman) is doing a great job. We, at Paisanos, have already done several tests in the LAB with incredible results.

Lynx: Created by ByteDance, Lynx is a Rust-backed framework that seeks to create universal applications inspired very strongly by web and the use of CSS. They seek to combine the best of the web with the fluid experience of a native app. Although it is still in a very early stage, its appearance resonates a lot in the community and is one of the most promising bets.

Expo: Expo continues to be the king of universal apps, especially with their latest version 52. Not just because of the router, but because of their EAS service that makes deploying these apps very easy and their continued contribution to the mobile/universal community.

Some of the things they are working on are:

- Dom Elements: A way to use web components in mobile applications in a simple way. It helps especially in migration processes where you are moving your web to something native, or if you need to use some specific web library in mobile (for example, using charts).
- Universal React Server Side Components: Expo is trying to bring Server Components universally, helping us to handle data, API calls and rendering without loading on the client. It's a huge change for those who want to build universal applications with SSR capabilities.

Vercel

The company that won the Web recently announced that Fernando Rojo (creator of Moti and Solito) joined its ranks as Head of Mobile. Not much is said about what he is doing there, but we can assume two things:

- It was recently announced that they were working on bringing v0 to a mobile application, so possibly they are looking to bring the Vercel ecosystem to something native, so that users can interact easily from our cell phone.
- They may be wanting to join the battle of universal applications, since they have the talent and the capacity to do so. From my perspective, the best way to join today is to make some tooling for handling hybrid applications in React Native, taking a Nextjs optimized here, since currently the performance of animations or interactions on the web is very good and can be imperceptible if it is embedded. The other way is to make a new framework for Mobile, but I think it is very expensive and it is a bet that maybe takes them out of their value proposition.

In any case, it would be great to see what Vercel has to contribute to the ecosystem, as they have done amazing things on the web.

This is just the beginning

Many of the frameworks mentioned are still in experimental or beta phase. They still need time to mature to reach stable releases that will allow them to reach their full potential. The race is just beginning, with Expo setting the pace, but with new competitors ready to enter the game and explore this fascinating world.

What is clear: the future is bright. And I have no doubt that 2026 will be the year that universal apps become the norm.

In the meantime, keep exploring, testing, breaking things. Every feedback we give as developers pushes these frameworks forward. It's our tests, our edge cases, and our actual uses that give them direction.

And that, too, is part of building the future.

Thanks for reading

Stay curious