How to Create a Website App with React Native and Expo
Learn how to create a website app using a modern, mobile-first approach with React Native and Expo. This guide covers setup, auth, AI, and deployment.

So, you want to build a website that feels like a native app? You're in the right place. The idea is to use a modern stack like React Native and Expo to build your application once and then ship it everywhere—as a high-performance website, an iOS app, and an Android app, all from a single codebase. This isn't your typical web development workflow; it's about blending mobile-first technology with web capabilities to get your product out the door faster on every platform.
Why Build a Website App with React Native?
Imagine writing your code just one time and watching it run flawlessly across every device. That's the real promise behind creating a "website app" with React Native. It’s a powerful approach that simply treats the web as another target for your mobile app. What you get is a website that feels as snappy and fluid as a native application.
This method is catching on fast, especially with startups and solo developers who need to move quickly and efficiently. Instead of juggling three separate projects—one for iOS, one for Android, and another for the web—you’re managing just one. We're not just talking about sharing a few components here and there; it's about building everything inside one powerful ecosystem.
The Power of a Unified Codebase
When you build a universal app this way, you unlock some serious advantages that traditional web development just can't offer:
- A Truly Consistent User Experience: Your users get the same design, feel, and features whether they're on their iPhone, Android tablet, or desktop browser.
- Insanely Fast Development Cycles: Fix a bug or add a new feature, and you only have to do it once. The update rolls out across all platforms simultaneously, which is a massive time-saver for both development and long-term maintenance.
- Tap into a Massive Ecosystem: You get full access to the huge, active React Native community and its endless supply of libraries and tools originally designed for mobile.
The real magic here is applying mobile-first design principles directly to the web. You end up with an incredibly fast, interactive experience. Better yet, you can easily configure it as an installable Progressive Web App (PWA), giving it offline capabilities and a permanent spot on your user's home screen.
Tapping into a Growing Market
Let's be honest, the demand for top-notch mobile and web experiences is through the roof. The global mobile app development market is exploding, projected to jump from $252.89 billion in 2023 to a staggering $1.1 trillion by 2034. This growth is all about mobile-first thinking and the big shift to digital-first solutions. If you want to dive deeper, you can check out more mobile app development statistics on RaasCloud.io to see where the market is headed.
Learning how to build a website app puts you in a perfect position to meet this demand without tripling your workload. And by using a starter kit like AppLighter, you can skip all the painful initial setup and start with a solid, production-ready foundation from day one. It lets you focus on what really matters: building your product, not messing with configuration files.
Alright, let's ditch the boilerplate and get our hands dirty. Instead of losing a week to manual setup, we’re going to use the AppLighter CLI to spin up a complete, production-ready project in about 2 minutes. This is where the theory stops and the real building begins.
With just one command, you're not just getting a few template files; you're scaffolding an entire monorepo. This thing comes pre-wired with an Expo frontend, a Hono backend, and authentication that actually works out of the box. The whole point is to bypass the tedious configuration grind and jump straight into building features people will use.
The goal here is a truly universal app. You write your code once, and it runs everywhere.
Diagram illustrating universal app development hierarchy: a single codebase branches to iOS, Android, and Web platforms.
This setup is the modern way to build. One React Native codebase powers your native iOS app, your Android app, and your website-app, saving an incredible amount of time and effort.
Scaffolding Your New App
Getting started is as simple as running a single command in your terminal. The AppLighter CLI will prompt you for a project name, and then it gets to work, building out the entire directory structure for you.
What you end up with is a clean, organized monorepo. This architecture is intentionally designed to keep your frontend and backend code separate but still tightly integrated, which is a lifesaver for managing complex projects.
Understanding the Monorepo Structure
Once the CLI finishes its magic, you'll have a new project folder waiting for you. Diving in, you’ll see a structure that’s been thoughtfully organized for full-stack development. It might look like a lot at first, but it’s designed to make your life easier as the app grows.
To help you get oriented, here's a quick rundown of the main directories you'll be spending your time in.
AppLighter Project Structure Explained
| Directory/File | Purpose | What You'll Find Inside |
|---|---|---|
apps/expo | The frontend of your application. | Your screens, navigation setup (Expo Router), components, and UI assets. This is your React Native world. |
packages/api | Your backend server logic. | Hono API routes, business logic, middleware, and server-side functions. It’s built to be fast and deployable anywhere. |
packages/db | Database schema and configuration. | Your database migration files, type definitions (like for a todos table), and client connection settings. |
packages/validators | Shared data validation rules. | Schemas (e.g., using Zod) to validate API inputs and form data, ensuring consistency across the stack. |
This setup is fantastic for team collaboration. A frontend developer can live inside apps/expo without ever needing to touch the API code, while a backend engineer can focus entirely on packages/api. It’s all in one repository, but the boundaries are crystal clear.
What's Included Out of the Box
This starter kit is more than just an empty folder structure. It comes packed with essential features that typically take days, if not weeks, to get right.
You're starting with a solid foundation that already includes:
- A Complete Authentication Flow: User sign-up, sign-in, and session management are already fully implemented using Supabase Auth. No need to build it from scratch.
- Universal Navigation: Expo Router is configured for file-based routing that works identically on the web, iOS, and Android.
- Ready-to-Use State Management: A simple but powerful state management solution is in place, so you can start managing application data immediately.
- Shared TypeScript Types: A dedicated package ensures your frontend and backend speak the same language, which drastically reduces bugs caused by data mismatches.
This isn't just boilerplate. It’s an opinionated, battle-tested starting point. It lets you skip the boring parts and focus your creative energy on what makes your website-app unique.
Alright, with your project up and running, it's time to dive into the fun part: building the features that actually make it feel like an app. We'll start with two of the most critical pieces of the puzzle: authentication and navigation. A solid website app needs to know who its users are and make it effortless for them to get around.
A professional desk setup featuring an iMac, smartphone app, keyboard, and plant, with an 'Auth & Navigation' banner.
Luckily, the AppLighter starter kit has already done most of the heavy lifting for us. It comes right out of the box with a fully wired-up authentication system using Supabase and a slick file-based navigation setup thanks to Expo Router. Our job isn't to reinvent the wheel, but to understand how these pieces work so we can bend them to our will.
Mastering Authentication with Supabase
Let's be honest, user authentication can be a real headache. You have to worry about everything from securely hashing passwords to managing user sessions. This is where the pre-configured Supabase integration is a lifesaver. Supabase handles all that backend complexity, leaving us with simple functions to call from our frontend.
Right away, the authentication flow in your apps/expo directory has you covered with screens for:
- Sign-Up: A new user can create an account with just an email and password.
- Sign-In: Existing users can log back in to access their stuff.
- Session Management: The app automatically keeps users logged in, even after a browser refresh.
What if you want to add a new feature, like an "Update Password" page? You don't need to spin up a new API endpoint. You just need to call the right function from the Supabase client library in a new screen component, and the integration takes care of the rest securely. It's a massive shortcut.
Navigating Your App with Expo Router
Great navigation is what makes a website app feel intuitive and professional. Expo Router completely changes the game here by using a file-based system, which you might recognize if you've ever worked with a framework like Next.js. The idea is brilliant in its simplicity: your app's route structure is a direct reflection of your project's file structure.
Every file you create inside the app directory automatically becomes a route in your application. It’s that straightforward.
You want a new screen? Just create a new file. To add an
/aboutpage to your site, you literally just create anabout.tsxfile inside theappdirectory. Expo Router handles all the magic to make that a navigable route on both web and mobile.
This approach keeps your navigation logic incredibly clean and directly tied to your codebase, making it a breeze to manage, even as your app starts to grow.
Building Practical Navigation Flows
Okay, let's put this into practice with a real-world scenario. Almost every app has certain areas that should only be accessible to logged-in users, like a personal dashboard. We can set this up in a clean, scalable way using Expo Router's layout routes.
A layout route (usually a file named _layout.tsx) can act as a wrapper for a whole group of files, applying shared UI or, in our case, logic.
Implementing Protected Routes
- First, create a route group. Inside the
appfolder, make a new folder and name it(protected). Those parentheses are special—they tell Expo Router this folder is for organization and shouldn't be part of the URL. - Next, add a layout file. Inside
(protected), create a_layout.tsxfile. This is where you'll put your gatekeeper logic. You can check for an active user session, and if there isn't one, you can programmatically redirect the user to your/sign-inscreen. - Finally, create your protected screens. Any screen file you put inside that
(protected)folder, likedashboard.tsxorsettings.tsx, will now be automatically protected by the logic you just wrote in your layout file.
This pattern is fantastic because it's so scalable. You can easily create different groups for different user roles, like an (admin) group and a (user) group, each with its own specific rules.
The demand for smooth, app-like web experiences is only getting bigger. Global app downloads are projected to rocket past 300 billion by 2025, with users spending a mind-boggling 4.2 trillion hours in apps this year alone. Nailing core features like authentication and navigation is your ticket to capturing some of that engagement. You can dig into more of these mobile app download and usage statistics to see just how big the opportunity is.
By tapping into these pre-built systems, you can quickly build a secure and well-structured website app without getting bogged down in boilerplate. That frees you up to focus on what really matters: the unique features that will make your project stand out.
Making Your App Come Alive with a Modern API Backend
A slick user interface is a great start, but it's only half the story. For your website-app to become truly useful—to save user data, process information, or connect with other services—it needs a solid backend. This is where the AppLighter starter kit really proves its worth, giving you a pre-configured, high-performance API layer right out of the box.
Instead of a traditional, monolithic server, you get a lightweight API built with Hono. Hono is engineered to be incredibly fast and run on edge networks, meaning your API can respond from a server that's physically close to your users. This simple fact slashes latency and makes your app feel exceptionally snappy, no matter where in the world someone is using it.
Defining Your First API Endpoint
All the backend magic happens inside the packages/api directory. You’ll find a simple, file-based routing system here, which makes adding new API endpoints feel completely natural.
Let's walk through a practical example: building a simple "notes" feature where users can create and view their own notes.
First up, we need an endpoint to fetch all the notes for a logged-in user. You'd start by creating a new file, say notes.ts, inside the API routes directory. In that file, you'll define a route that listens for GET requests. The logic inside would then query your database (which is already connected) to pull all notes associated with the current user's ID.
This structure keeps your backend code incredibly organized. All the logic for your notes feature—creating, reading, updating, and deleting—can live together in one spot. It’s a clean approach that’s easy to manage as your app gets more complex.
Building Out a Full CRUD Feature
Of course, a real feature needs more than just fetching data. It requires the full suite of CRUD operations: Create, Read, Update, and Delete.
Here’s how our notes.ts API file would map out these operations:
GET /notes: Fetches all notes for the authenticated user. We've got this one planned.POST /notes: Creates a new note. The request body will contain the note's content, and our backend logic will insert it into the database, linking it to the user.PATCH /notes/:id: Updates an existing note. This route takes a note ID as a parameter and the new content in the request body.DELETE /notes/:id: Deletes a specific note by its ID.
This is a standard, restful pattern that’s easy for any frontend to work with. The Hono framework makes defining these routes clean and straightforward, often just a few lines of code per operation.
The real game-changer here is the seamless integration. Since the API and frontend live in the same monorepo, you can share TypeScript types between them. If you define a
Notetype for your database, your frontend automatically knows the exact structure of the data it will get from the API. This catches potential bugs before they ever see the light of day.
Calling the API from Your React Native Frontend
With our backend endpoints ready to go, it's time to call them from our React Native app, located in the apps/expo directory. This is where everything comes together. AppLighter ships with a pre-configured API client that makes fetching data a breeze.
To show the notes, you might create a NotesScreen.tsx component. Inside it, you’d use a custom hook to call the GET /notes endpoint as soon as the screen loads. The data that comes back—an array of notes—can be stored in your app's state and then rendered into a list for the user to see.
Creating a New Note
Now, picture a simple form on that screen with a text input and a "Save Note" button. When a user clicks that button, the logic in your component would:
- Grab the text from the input field.
- Call a function that fires off a
POSTrequest to your/notesAPI endpoint. - Pack the new note's content into the body of that request.
As soon as the API confirms the note is saved, your frontend can instantly refresh the list, and the new note appears. This tight feedback loop between a frontend action and its backend counterpart is what creates a smooth, dynamic experience for your users.
This whole workflow—from defining an API route in the backend to displaying its data on the screen—happens inside a single, cohesive ecosystem. You're not juggling separate repositories, fighting with version mismatches, or wrestling with CORS headaches. It's all designed to work together from day one, helping you build full-stack features faster than ever.
Bringing in AI to Speed Up Your Development
Let's be real—"AI" is a term that gets thrown around a lot. But when you're actually building a website app, you don't need hype; you need tools that genuinely make your life easier. The goal is to get AI to handle the grunt work so you can focus on building cool stuff. This is exactly what AppLighter’s built-in AI tooling is designed for.
Instead of wrestling with APIs and complex configurations, the starter kit gives you powerful systems ready to go from day one. It’s all about making AI feel like a natural part of your coding process, not just another thing to learn.
Keep Your Codebase Clean with Claude
We've all been there: trying to maintain consistent code quality across a project feels like a full-time job. Manual reviews take time, and debates over style can drag on forever. AppLighter helps you sidestep that mess by integrating pre-configured Claude Code rules.
Think of these as more than just your standard linter. They’re smart, context-aware guidelines that automatically enforce best practices. For example, a rule might spot a component that's getting a bit too bloated and suggest a better way to manage its state. It’s like having a senior developer giving you pointers as you go, helping you write cleaner, more stable code without slowing you down.
Get AI Help Right Inside Your Editor
Hopping between your code editor, a browser tab, and documentation is a classic productivity killer. To solve this, AppLighter comes with Cursor plugins baked right in. This puts AI assistance directly where you're working.
Need to refactor a messy function or generate some boilerplate for a new component? Just ask. You can even use natural language to debug a tricky piece of logic without ever leaving your editor. Imagine highlighting some code and typing, "add proper error handling and TypeScript types to this." The AI takes care of it, and you can get back to solving the real problem.
The whole point is to weave AI so tightly into your workflow that it feels like an extension of your own brain. It’s not about replacing developers; it’s about augmenting them. Let the machine handle the repetitive tasks so you can stay in the creative zone.
Let's Build an AI-Powered Feature
Alright, let's see how this all comes together in practice. A great example is building a feature that processes user-generated content, like an automatic text summarizer.
Using the Hono backend set up in your packages/api directory, here’s how you could pull it off:
- First, you'd create a new API route, maybe something like
/summarize. - Inside that route's handler, you'll make a call to an external LLM API, sending the user's text along with the request.
- Finally, you'll return the AI-generated summary as a simple JSON response.
Back on the frontend, your React Native app just needs to hit this /summarize endpoint. The user types their text, hits a button, and gets a neat summary back almost instantly. This is the kind of feature you can often knock out in less than an hour, which really shows how quickly you can add powerful AI capabilities.
This move toward faster, smarter development is happening everywhere. Low-code and no-code platforms are becoming incredibly popular, with some projections showing they’ll be used for 75% of new app development by 2026. The market itself is expected to grow from $37.39 billion in 2025 to a massive $264.40 billion by 2032.
You can explore more on how mobile app development trends are evolving at lovable.dev. By building with AI from the ground up, you’re not just coding faster—you’re working smarter and staying ahead of the curve.
Deploying Your Website App as a PWA
Alright, you've done the heavy lifting. The core features are in, the API is talking to your app, and you've even woven in some AI magic. Now comes the best part: getting your creation out into the world. We're moving beyond localhost and into a live, production-ready website app that anyone can use.
A hand holding a smartphone showing 'Installable PWA' and a laptop in the background with 'Add To Home Screen' option.
But we're not just putting a website online. The goal is to ship a fully-fledged Progressive Web App (PWA). This simple shift gives your project an app-like feel, complete with home screen icons and offline functionality, blurring the line between web and native. Let’s walk through the final checks and flip that PWA switch.
Test Before You Launch
Putting code into the wild without testing is a recipe for disaster. While a full dissertation on testing is for another day, there are a few essential pre-flight checks you absolutely have to run. Think of this as your final quality control pass.
Here’s a quick but effective checklist I run through before every launch:
- Browser Sanity Check: Fire up your app in Chrome, Firefox, Safari, and Edge. You'd be surprised how often a small CSS quirk in one browser can break your entire layout in another.
- Responsive Design Audit: Pop open your browser's developer tools and start resizing that viewport. Test everything from a tiny iPhone SE to a massive desktop monitor. Your UI needs to look good and work well everywhere.
- Performance Deep Dive: Run a Google Lighthouse report. This is non-negotiable. It gives you hard data on speed, accessibility, and SEO. A good target to aim for is a score above 90 in the key categories.
Trust me, an hour spent on these checks can save you days of frantic bug-fixing and reputation management down the road.
Creating a Production-Ready Build
Once you’re satisfied with your testing, it's time to create an optimized build. This command takes all your development code and crunches it down into a tight package of static HTML, CSS, and JavaScript files perfect for a production server.
Expo makes this ridiculously simple. A single command in your terminal kicks off the web build process. Under the hood, the bundler is doing some serious optimization work, like code splitting and minification, to make sure your app is as lean and fast as possible.
When it finishes, you’ll find a dist (or web-build) folder in your project. These are the files you'll actually upload to your host. That’s it.
Deploying with Vercel or Netlify
Now, let's get this thing online. For projects like this, forget old-school FTP. Platforms like Vercel and Netlify are the way to go. They're built for modern web development and connect directly to your code repository for a buttery-smooth workflow.
The process is refreshingly straightforward:
- Push your project code to a GitHub, GitLab, or Bitbucket repository.
- Sign up for Vercel or Netlify and connect it to your Git provider.
- Point the platform to your project's repository. It's usually smart enough to detect an Expo app automatically.
- Configure the build command to
npx expo export:web. - Tell it that the output directory is the
distfolder generated earlier.
Once configured, any time you push a change to your main branch, your app will automatically be rebuilt and deployed. This "GitOps" workflow is a game-changer; you can just focus on your code.
Activating PWA Capabilities
This is the final touch that elevates your project. Turning your Expo app into a PWA feels almost like cheating because the framework does all the complicated work for you.
At the heart of any PWA are two key files: a service worker and a web app manifest.
- The Service Worker: Think of this as a background script that your browser runs. It’s what intercepts network requests and caches your app’s assets, making offline access possible.
- The Web App Manifest: This is a simple JSON file that tells the browser about your app—its name, icon, theme colors, etc.—so it knows how to "install" it onto a device.
To enable PWA mode in Expo, you just make one tiny change to your
app.jsonfile. Find theweb.bundlersetting and add"pwa". That's it. This one-line change instructs Expo to generate a service worker and handle all the registration for you.
With PWA mode enabled, you can then flesh out the web section in app.json to customize the manifest. Here you can set your app’s public-facing name, define a theme color for the browser UI, and point to the icons you want used on the user’s home screen.
With these changes in place, build and deploy one last time. Now, when someone visits your site on a supported browser (like Chrome on Android or Safari on iOS), they'll get a prompt to "Add to Home Screen." When they tap it, your website app gets its own icon, ready for instant access right from their device. You've officially launched a true website app.
A Few Common Questions
When you're diving into a new stack to build a website app, a few questions always come up. Here are some of the most common things developers ask when they first get their hands on this workflow.
Can I Just Build a Web App With This?
Absolutely. Even though this entire setup is built for creating universal apps, you can easily use it just for the web.
All you have to do is focus your work inside the apps/expo package and only run the web development server. The backend and shared packages will work exactly the same, giving you a powerful, organized workflow whether you’re targeting one platform or all of them.
How Much Work Is It to Swap Out the Database?
We designed the architecture to be as modular as possible for this exact reason. The Hono API layer in packages/api is your secret weapon here—it creates a clean separation between your frontend and your database.
If you wanted to switch from the default Supabase setup, you'd just need to update the logic inside your API routes. Your frontend code doesn't care how it gets the data, only that it gets it from the API. That means your UI would remain almost entirely untouched, saving you from a massive refactoring project.
The big idea here is that the backend API is decoupled from the frontend UI. This separation lets you swap out major infrastructure pieces, like your database, without having to tear apart your entire application.
How's the Performance of React Native for Web?
That's a fair question, and the good news is that Expo for Web has come a long way. It's gotten really smart about translating your React Native components into high-performance HTML elements that browsers love.
To get the best results, you still need to follow standard web best practices. Think of things like:
- Code Splitting: Expo Router helps with this out of the box, so users only download the code for the page they're actually on.
- Image Optimization: Always serve properly sized and compressed images. It makes a huge difference.
- Lazy Loading: Don't load components and other assets until the user actually needs to see them.
This starter kit is already configured with performance in mind, but I always recommend running your app through a tool like Lighthouse to hunt down any specific bottlenecks.
Is a PWA Really as Good as a Native App?
It honestly depends on what you're building. For many projects, a Progressive Web App (PWA) delivers an amazing, near-native experience. You get offline access, home screen installation, and push notifications—all without dealing with app store approvals. For a lot of businesses, that's the perfect sweet spot.
However, true native apps will always have better access to the latest and greatest device hardware or niche platform-specific APIs. The real magic of this stack is that you don't have to choose. You can build both from the exact same codebase. You could launch a PWA first and then ship a native app later on without ever having to start from scratch.
Ready to stop wrestling with configuration and start building? With AppLighter, you get a production-ready starter kit that handles the tedious setup for you. Get your universal app off the ground in minutes at https://www.applighter.com.