Building applications for both web and mobile has traditionally required maintaining separate codebases, duplicating logic, and managing entirely different navigation paradigms. Web applications use flat URL-based routing with browser history, while mobile apps rely on nested navigation stacks with modals, tabs, and deep linking.
Solito bridges this gap by providing a unified navigation API that works seamlessly across React Native and Next.js, allowing developers to share code and patterns across platforms while respecting each platform's native behaviors. In this guide, we'll explore how to build cross-platform applications using Solito, covering setup, navigation patterns, platform-specific code handling, and the significant changes introduced in Solito 5's web-first approach.
For teams building comprehensive digital solutions, our web development services incorporate modern cross-platform approaches alongside traditional web applications. Similarly, our mobile app development services leverage tools like Solito to deliver applications that work seamlessly across iOS, Android, and web browsers.
Key benefits that make Solito the preferred choice for unified web and mobile development
Unified Navigation API
Write navigation code once that works identically on web and native platforms. Solito translates a single API into URL-based routing for web and native navigation stacks for mobile.
Reduced Development Time
Ship to both web and mobile from a single codebase. A small team can maintain applications on multiple platforms without hiring specialists for each environment.
Platform-Native Experience
Respect each platform's conventions. Web uses standard anchor tags for SEO and accessibility; mobile uses native navigation with proper gestures and transitions.
Active Community
Backed by a growing community of cross-platform developers. Extensive documentation, starter templates, and community patterns help you get started quickly.
Understanding the Solito Monorepo Architecture
The recommended structure for a Solito project is a monorepo that separates web and native codebases while sharing common application logic. This architecture allows each platform to use its optimal tooling--Next.js for web with server-side rendering, and Expo or React Native CLI for mobile--while keeping business logic, API integrations, and navigation patterns in shared packages.
Monorepo Structure
my-solito-app/
├── apps/
│ ├── next/ # Next.js web application
│ └── native/ # Expo/React Native app
└── packages/
├── ui/ # Shared UI components
├── features/ # Shared feature modules
└── utils/ # Shared utilities
This separation ensures that shared code remains platform-agnostic, using only APIs and components that exist in both React Native and React for web. The monorepo approach also integrates well with our digital transformation services, which help organizations modernize their technology stack and adopt unified development practices.
The packages directory typically contains shared UI components forming the foundation of code sharing, allowing buttons, cards, forms, and other interface elements to be written once and used on both platforms. Application logic including state management, API calls, validation, and business rules resides in shared utility packages. Navigation configuration, including route definitions and screen components, can also be shared across platforms, with Solito handling the platform-specific translation of navigation code. For teams exploring efficient design system implementation, our guide on creating faster design systems with Tamagui provides complementary insights into cross-platform styling approaches.
Installation and Initial Setup
Getting started with Solito involves setting up a new monorepo or integrating Solito into an existing project structure. For new projects, the official Solito starter template provides a pre-configured monorepo with Next.js for web, Expo for mobile, and all necessary shared packages pre-configured. This template serves as a reference implementation and can be customized to fit specific project requirements.
Required Dependencies
Web Application:
- Next.js 14+
- React + ReactDOM
- @solito/navigation
Native Application:
- React Native
- React Navigation (stack, tabs, drawer)
- @solito/navigation
Shared Packages:
- Platform-agnostic dependencies
- Solito components and hooks
The installation process requires careful attention to version compatibility. Solito provides compatibility documentation that specifies which versions of React Navigation, Expo, and Next.js work together. Configuration of the shared packages involves ensuring that both the web and native applications can import from the shared code without issues. TypeScript configurations should be consistent across the monorepo, with a base tsconfig.json in the root that extends into each application and package.
Core Navigation Concepts in Solito
Solito's navigation system is built around unified routing--a single API that translates into the appropriate navigation mechanism for each platform. At its core, Solito provides a Link component that works like a standard anchor tag on the web but uses React Navigation's imperative navigation on native devices.
The Link Component
The Link component is the foundation of navigation in Solito applications:
// Basic navigation
<Link href="/dashboard">Dashboard</Link>
// With parameters
<Link href="/users/[userId]" as="/users/123">
User Profile
</Link>
// With query parameters
<Link href="/products?category=electronics">
Electronics
</Link>
On the web, Link renders as an anchor tag with the correct href attribute, supporting browser features like right-click to open in new tab and proper SEO indexing. On native, Link renders as a touchable component with appropriate press handlers, using React Navigation to perform the navigation action.
useRouter Hook
Imperative navigation with the unified useRouter hook:
import { useRouter } from 'solito/router'
function MyComponent() {
const router = useRouter()
const handlePress = () => {
router.push('/products')
router.replace('/login')
router.back()
}
return <Button onPress={handlePress}>Go Products</Button>
}
The useRouter hook provides imperative navigation capabilities and access to routing state. It returns a navigation object with methods like push, replace, back, and navigate, along with route information including the current pathname, query parameters, and asPath. The hook handles the platform differences internally, so components using useRouter work identically regardless of whether they're running on web or native.
Platform-Specific Code with .native.tsx Files
Solito supports platform-specific code through file extensions, allowing you to write components that use platform-specific APIs while maintaining a clean, declarative structure. By naming a file with the .native.tsx extension, you indicate that this file should only be included in the native application build, completely excluded from the web build.
How It Works
MyComponent.tsx # Shared (both platforms)
MyComponent.native.tsx # Native only
MyComponent.web.tsx # Web only (Solito 5)
Example: Platform-Specific Touchable
// MyComponent.tsx (shared interface)
export { MyTouchable as default } from './MyTouchable.native'
// MyTouchable.native.tsx (native implementation)
import { TouchableOpacity, Platform } from 'react-native'
export function MyTouchable({ onPress, children }) {
return (
<TouchableOpacity onPress={onPress} activeOpacity={0.7}>
{children}
</TouchableOpacity>
)
}
// MyTouchable.web.tsx (web implementation)
export function MyTouchable({ onPress, children }) {
return (
<button onClick={onPress} className="touchable">
{children}
</button>
)
}
This file extension-based approach is more maintainable than runtime platform checks because the bundler removes unreachable code entirely, reducing bundle size and improving performance. Platform-specific components are essential for features that differ fundamentally between web and native platforms. Understanding this pattern is crucial for building robust cross-platform applications that perform optimally on each target platform.
Solito 5: The Web-First Approach
Solito 5 represents a significant evolution in the framework's philosophy, introducing a web-first approach that simplifies integration with Next.js and removes dependencies that complicated web builds. The most notable change is the removal of react-native-web as a required dependency. Previous versions of Solito relied on react-native-web to render React Native components on the web, which required complex bundler configuration.
Key Changes in Solito 5
- Removed react-native-web dependency - Web apps use pure React and HTML, not React Native components
- Simpler bundler configuration - No complex webpack configuration needed
- Cleaner separation - Web and native codebases are truly independent
- Better Next.js compatibility - Works with latest Next.js features including App Router
File Extension Changes
| Solito 4 | Solito 5 |
|---|---|
| Default (.tsx) → Web | Default (.tsx) → Web |
| .web.tsx → Web | (not needed) |
| .native.tsx → Native | .native.tsx → Native |
Migration Benefits
- Pure Next.js web application with full feature compatibility
- Reduced bundle complexity
- Easier debugging and testing
- Better performance on both platforms
Web applications built with Solito 5 are pure Next.js applications, meaning they benefit from all Next.js features including the App Router, Server Components, and the latest performance optimizations without any compatibility workarounds. Teams building with modern web technologies can leverage our web development expertise to implement Solito and other cutting-edge frameworks effectively.
Building a Cross-Platform App: Step-by-Step
Step 1: Define Your Navigation Structure
Map out all screens and their relationships--modals, tabs, deep linking routes, and parameter passing. Route names should be chosen to be URL-friendly for web while remaining clear and descriptive:
// navigation.ts
export const RootStack = createNativeStackNavigator({
screens: {
Home: '/',
Profile: '/profile',
ProfileEdit: '/profile/edit',
ProductDetails: '/products/[productId]',
},
})
Step 2: Create Shared Screens
Write screen components that work on both platforms using only cross-platform APIs and styling:
// screens/HomeScreen.tsx
export function HomeScreen() {
return (
<View>
<Text>Welcome to My App</Text>
<Link href="/profile">View Profile</Link>
</View>
)
}
Step 3: Handle Platform Differences
Use .native.tsx files when platform-specific behavior is required:
// screens/HomeScreen.native.tsx
import { ScrollView } from 'react-native'
export function HomeScreen() {
return (
<ScrollView>
<Text>Welcome to My App</Text>
<Link href="/profile">View Profile</Link>
</ScrollView>
)
}
Step 4: Implement Data Layer
Use unified data fetching with libraries like React Query that work consistently across platforms. Our API development services can help design robust backend services that power your cross-platform applications with consistent, reliable data access.
Building cross-platform applications requires careful attention to user experience across all platforms. Following digital product design best practices ensures your Solito application delivers intuitive experiences whether users access it via web browser or native mobile app.
Best Practices for Solito Development
1. Abstraction of Platform Logic
Isolate platform-specific code into shared hooks rather than checking Platform.OS throughout components:
// hooks/useUserPreferences.ts
export function useUserPreferences() {
const platform = Platform.OS
if (platform === 'web') {
// Web-specific implementation
return useWebPreferences()
}
// Native implementation
return useNativePreferences()
}
2. Consistent Styling System
Use a unified styling system like Tamagui that compiles to both CSS and React Native StyleSheet. This ensures visual consistency across platforms while allowing for platform-specific adjustments:
import { YStack, Text } from 'tamagui'
export function Card({ children }) {
return (
<YStack padding="$4" borderRadius="$2" backgroundColor="$background">
{children}
</YStack>
)
}
For teams implementing design systems at scale, our guide on creating faster design systems with Tamagui provides detailed insights into cross-platform styling strategies that complement Solito development.
3. Unified Data Fetching
Use React Query or SWR for consistent data fetching across platforms:
import { useQuery } from '@tanstack/react-query'
export function useProducts() {
return useQuery({
queryKey: ['products'],
queryFn: fetchProducts,
})
}
4. Deep Linking Configuration
Configure deep linking to enable users to open specific screens directly from URLs, notifications, or other apps. This is essential for mobile applications that need to integrate with other apps and services.
Deep Linking and URL Handling
Deep linking enables users to open specific screens directly from URLs, notifications, or other apps. Solito handles deep linking through configuration of the React Navigation linking API, which maps URL patterns to navigation state.
Configuration
// native/linking.ts
import { createLinkingConfig } from 'solito/navigation'
export const linking = createLinkingConfig({
screens: {
Home: '',
ProductDetails: 'products/:productId',
UserProfile: 'users/:userId',
},
})
// In app.config.ts (Expo)
export default {
expo: {
scheme: 'myapp',
plugins: [
[
'expo-linking',
{
schemes: {
myapp: ['myapp'],
},
},
],
],
},
}
URL Structure Best Practices
- Use descriptive, SEO-friendly URLs for web
- Map URLs to navigation stacks for native
- Use query parameters for optional filters
- Test deep links on both platforms
URL structure for Solito applications should be designed to work well on both web and mobile. The web URL becomes the canonical identifier for content, so it should be SEO-friendly and descriptive. The same URL structure should map cleanly to mobile navigation stacks, with the path segments corresponding to screens in the navigation hierarchy. Proper URL handling is essential for web application security and user trust.
Frequently Asked Questions
Sources
- Solito Official Documentation - Official documentation covering installation, API, and methodology
- LogRocket: Build a React Native app with Solito - Step-by-step guide with code examples for building a news app with Solito
- DEV Community: Solito 5 is now web-first - Coverage of Solito 5 web-first changes and platform-specific file handling