Skip to content

JoeSlain/Nexpo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

52 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

NEXPO banner

A production-ready monorepo template for building cross-platform applications with Next.js and React Native (Expo)

Based on Fernando Rojo's work

🎯 Quick Start

⚑️ Instantly clone & deploy on vercel

(You still need to setup supabase manually)

Deploy with Vercel

Manual setup

  1. Click "Use this template" on GitHub
  2. Clone your new repository
  3. Follow the Setup Instructions below

πŸ“¦ What's Included

  • Solito - Cross-platform navigation between Next.js and React Native
  • Next.js 16 - React framework for production
  • Expo SDK 54 - React Native framework
  • React 19 with React Compiler
  • tRPC - End-to-end typesafe APIs
  • Supabase - Backend as a service (database, auth, storage)
  • Lingui - Internationalization (i18n)
  • Tamagui - Universal design system
  • Storybook - Component development and testing (web & native)
  • Testing - End-to-end (Playwright for web, Maestro for mobile), database (pgTAP), and API/integration (Vitest) tests
  • Sentry - Error tracking and monitoring
  • Turborepo - Monorepo build system
  • Biome - Fast formatter and linter
  • Husky - Git hooks

πŸ—‚ Project Structure

.
β”œβ”€β”€ apps/
β”‚   β”œβ”€β”€ expo/          # React Native app (Expo)
β”‚   β”œβ”€β”€ next/           # Next.js web app
β”‚   β”œβ”€β”€ storybook-native/  # React Native Storybook
β”‚   └── storybook-web/     # Web Storybook
β”œβ”€β”€ packages/
β”‚   β”œβ”€β”€ app/            # Shared app code (features, providers, navigation)
β”‚   └── api/            # tRPC router and Supabase server client
└── supabase/           # Supabase migrations and config

🏁 Setup Instructions

Prerequisites

  • Node.js 20+ and Yarn 4.7.0+
  • Docker (for local Supabase development)
  • Git

1. Install Dependencies

yarn install

2. Configure Environment Variables

This project uses environment-specific configuration files for development and production. Each app has separate .env.development and .env.production files.

Environment File Structure

Next.js (apps/next/):

  • .env.development - Development environment variables (auto-loaded when NODE_ENV=development)
  • .env.production - Production environment variables (auto-loaded when NODE_ENV=production)
  • .env.local - Local overrides (gitignored, highest priority, never commit this file)

Expo (apps/expo/):

  • .env.development - Development environment variables (loaded via helper script)
  • .env.production - Production environment variables (loaded via helper script)
  • .env.local - Local overrides (gitignored, highest priority, never commit this file)

Note: Next.js automatically loads environment files based on NODE_ENV. Expo uses a custom helper script (scripts/load-env.js) to achieve the same behavior.

Setup Instructions

  1. Update development values in apps/next/.env.development and apps/expo/.env.development:

    • Set your local Supabase URL: http://127.0.0.1:54321
    • Get your local Supabase anon key by running yarn supabase:status
    • For Expo, set EXPO_PUBLIC_API_URL to http://localhost:3000/api/trpc (or your machine's IP for physical devices)
  2. Update production values in apps/next/.env.production and apps/expo/.env.production:

    • Replace placeholder values with your actual production Supabase credentials
    • Set production API URLs
    • Configure production Sentry DSNs
  3. Create .env.local files (optional, for local overrides):

    # These files are gitignored and should contain only your local secrets
    touch apps/next/.env.local
    touch apps/expo/.env.local

Required Variables

Next.js:

  • NEXT_PUBLIC_SUPABASE_URL - Your Supabase project URL
  • NEXT_PUBLIC_SUPABASE_ANON_KEY - Your Supabase anon/public key
  • SUPABASE_SERVICE_ROLE_KEY - (Optional) For server-side operations with elevated permissions
  • NEXT_PUBLIC_SENTRY_DSN - (Optional) Sentry DSN for client-side error tracking
  • SENTRY_DSN - (Optional) Server-side Sentry DSN
  • SENTRY_ORG - (Optional) Sentry organization slug
  • SENTRY_PROJECT - (Optional) Sentry project slug

Expo:

  • EXPO_PUBLIC_SUPABASE_URL - Your Supabase project URL
  • EXPO_PUBLIC_SUPABASE_ANON_KEY - Your Supabase anon/public key
  • EXPO_PUBLIC_API_URL - Your Next.js API URL (for tRPC)
  • EXPO_PUBLIC_SENTRY_DSN - (Optional) Sentry DSN for error tracking

Root (for lingui-ai-translate):

  • OPENAI_API_KEY - (Optional) OpenAI API key for automated translations. Get your key from platform.openai.com

3. Setup Supabase

Local Development

Start Supabase locally:

yarn supabase:start

This will:

  • Start all Docker containers
  • Run database migrations
  • Load seed data

Get your local environment variables:

yarn supabase:status

Access Supabase Studio at: http://localhost:54323

Production Setup

  1. Create a project at supabase.com
  2. Get your project URL and API keys from the project settings
  3. Update your environment variables with production values
  4. Push your database schema:
# Link to your Supabase project (only needed once)
supabase link --project-ref your-project-ref

# Push migrations to production
supabase db push

⚠️ Important: The template includes a seed file. Review and modify supabase/seed.sql before deploying to production.

4. Update Supabase Project ID

Update the project ID in supabase/config.toml:

project_id = "your-project-name"

This helps distinguish different Supabase projects on the same machine.

5. Update API URLs

Expo tRPC Client

Update the production API URL in apps/expo/utils/trpc/client.tsx:

return process.env.EXPO_PUBLIC_API_URL || 'https://your-domain.com/api/trpc'

6. Start Development Servers

Web (Next.js)

yarn web

This will:

  • Automatically load .env.development and .env.local (if exists) based on NODE_ENV=development
  • Start the Next.js dev server
  • Run on http://localhost:3000

You can also run directly from the apps/next directory:

cd apps/next
yarn dev

Note: Next.js automatically loads environment files based on NODE_ENV. No dotenv-cli needed.

Mobile (Expo)

First, build a dev client:

cd apps/expo
yarn ios
# or
yarn android

Then, from the root:

yarn native

Or run directly from the apps/expo directory:

cd apps/expo
yarn start

The Expo scripts automatically load .env.development and .env.local (if exists) via the load-env.js helper script.

πŸš€ Deployment

Vercel (Next.js)

  1. Connect your repository to Vercel

  2. Set the root directory to apps/next

  3. Configure environment variables in Vercel dashboard:

    • NEXT_PUBLIC_SUPABASE_URL - Your production Supabase URL
    • NEXT_PUBLIC_SUPABASE_ANON_KEY - Your production Supabase anon key
    • SUPABASE_SERVICE_ROLE_KEY - Your production service role key
    • SENTRY_* - (Optional) Sentry configuration for production

    Note: Vercel automatically sets NODE_ENV=production during build, so Next.js will load .env.production automatically. However, you should set production values in Vercel's environment variables dashboard for security.

  4. Vercel will automatically detect:

    • Framework: Next.js
    • Build Command: cd ../.. && npx turbo run build --filter=next-app
    • Output Directory: .next

Or use the deploy button above after updating the repository URL.

Expo (Mobile Apps)

Deploy using EAS (Expo Application Services):

Prerequisites

  1. Install EAS CLI:

    npm install -g eas-cli
  2. Login to EAS:

    eas login

Configuration

The eas.json file is already configured with build profiles:

  • development: Development client builds (simulator/APK)
  • preview: Internal distribution builds (APK)
  • production: Production app store builds (App Bundle/IPA)
  1. Configure environment variables in EAS:

    cd apps/expo
    eas secret:create --scope project --name EXPO_PUBLIC_SUPABASE_URL --value "https://your-project.supabase.co"
    eas secret:create --scope project --name EXPO_PUBLIC_SUPABASE_ANON_KEY --value "your-production-anon-key"
    eas secret:create --scope project --name EXPO_PUBLIC_API_URL --value "https://your-domain.com/api/trpc"
    eas secret:create --scope project --name EXPO_PUBLIC_SENTRY_DSN --value "your-sentry-dsn"  # Optional

    Or configure them in the EAS dashboard.

  2. Update submit credentials (optional, for automated submissions): Edit apps/expo/eas.json and update the submit.production section with your:

    • Apple ID, App Store Connect App ID, and Team ID (for iOS)
    • Google Play service account key path (for Android)

Build and Submit

  1. Build for production:

    cd apps/expo
    
    # Build for iOS
    npm run eas:build:ios:profile
    
    # Build for Android
    npm run eas:build:android:profile
    
    # Build for both platforms
    npm run eas:build:all -- --profile production
  2. Submit to app stores:

    cd apps/expo
    
    # Submit iOS build
    npm run eas:submit:ios
    
    # Submit Android build
    npm run eas:submit:android

OTA Updates

Publish over-the-air updates without rebuilding:

cd apps/expo

# Publish update to production channel
npm run eas:update:republish

# Or use interactive mode
npm run eas:update

Available EAS Scripts

The project includes several EAS-related scripts in apps/expo/package.json:

Build:

  • npm run eas:build:android - Build for Android
  • npm run eas:build:ios - Build for iOS
  • npm run eas:build:all - Build for both platforms
  • npm run eas:build:android:profile - Build Android with production profile
  • npm run eas:build:ios:profile - Build iOS with production profile

Submit:

  • npm run eas:submit:android - Submit Android build to Play Store
  • npm run eas:submit:ios - Submit iOS build to App Store

Update:

  • npm run eas:update - Publish OTA update (interactive)
  • npm run eas:update:republish - Publish update to production branch

Configuration:

  • npm run eas:configure - Configure EAS Build

πŸ”” Sentry Configuration

This template includes Sentry for error tracking. To enable:

  1. Create a project at sentry.io
  2. Get your DSN from project settings
  3. Set the environment variables (see above)
  4. Sentry will automatically initialize in both apps

🌍 Internationalization (i18n)

This template uses Lingui for i18n. Supported locales are configured in packages/app/lingui.config.js.

Workflow

The typical i18n workflow consists of three steps:

  1. Extract messages - Extract translatable strings from your code
  2. Translate messages - Translate messages using AI or manual translation
  3. Compile messages - Compile translations for runtime use

Extract messages

Extract translatable strings from your codebase:

yarn lingui:extract

This scans your code for t macros and other Lingui translation functions and generates .po files in packages/app/locales/.

Translate messages

Using AI Translation (Recommended)

This template includes lingui-ai-translate for automated translations using OpenAI's API.

Setup:

  1. Get your OpenAI API key from platform.openai.com

  2. Add it to your environment variables:

    For root .env (used by lingui-ai-translate):

    OPENAI_API_KEY=your-openai-api-key-here

    Or export it in your shell:

    export OPENAI_API_KEY=your-openai-api-key-here
  3. Run the translation command:

    yarn lingui:translate

This will automatically translate all messages in your .po files to all configured locales using OpenAI's API. The translations preserve placeholders and formatting.

Manual Translation

You can also manually edit the .po files in packages/app/locales/ to translate messages yourself.

Compile messages

After translating, compile the messages for runtime use:

yarn lingui:compile

This generates optimized .js files that are used by your application at runtime.

πŸ“š Storybook

This template includes Storybook for both web and React Native, allowing you to develop and test UI components in isolation.

Web Storybook

Start the web Storybook to view and test components in a browser environment:

yarn storybook:web

This will start Storybook on http://localhost:6006

React Native Storybook

Start the React Native Storybook to view and test components in a mobile environment:

yarn storybook:native

This will start Storybook on http://localhost:7007 and open the Expo app with Storybook UI integrated.

You can also run it directly from the apps/storybook-native directory:

cd apps/storybook-native
yarn storybook
# or run the Expo app directly
yarn ios
# or
yarn android

Story Locations

Stories are automatically loaded from:

  • apps/storybook-web/src/**/*.stories.tsx (web stories)
  • apps/storybook-native/src/**/*.stories.tsx (native stories)
  • packages/ui/src/**/*.stories.tsx (shared UI package stories)

Features

  • Tamagui Integration - Both Storybook apps use the shared Tamagui config from packages/app/tamagui.config.ts
  • Monorepo Support - Stories from shared packages are automatically loaded
  • TypeScript Support - Full TypeScript support for stories
  • Addons - Web Storybook includes accessibility, docs, and testing addons

Writing Stories

When writing stories that should work in both web and React Native:

import type { Meta, StoryObj } from '@storybook/react' // web
// or '@storybook/react-native' for native-only stories

import { YourComponent } from './YourComponent'

const meta = {
  title: 'UI/YourComponent',
  component: YourComponent,
  // ... rest of config
} satisfies Meta<typeof YourComponent>

export default meta

For platform-specific stories, use platform-specific story files or conditional imports.

πŸ§ͺ Testing

This template includes comprehensive testing infrastructure covering end-to-end tests (web and mobile), database tests, and API/integration tests.

Test Types

End-to-End (E2E) Tests - Web (Playwright)

Playwright-based end-to-end tests for the Next.js web application.

Location: apps/next/e2e/

Coverage:

  • Home page across all locales
  • User pages
  • API routes
  • Navigation and routing
  • Accessibility features

Run tests:

# From root
yarn test:e2e

# From apps/next directory
cd apps/next
yarn test:e2e

# Interactive UI mode
yarn test:e2e:ui

# Headed mode (see browser)
yarn test:e2e:headed

Documentation: See apps/next/e2e/README.md for detailed E2E testing guide.

End-to-End (E2E) Tests - Mobile (Maestro)

Maestro-based end-to-end tests for the Expo/React Native mobile application.

Location: apps/expo/.maestro/

Coverage:

  • Navigation (home screen, user detail screen)
  • Authentication (sign in, sign out, protected endpoints)
  • Theme (dark/light mode toggle)
  • Locale (internationalization and locale switching)
  • Integration (full user flows)

Prerequisites:

  1. Install Maestro CLI:

    # macOS
    brew tap mobile-dev-inc/tap
    brew install maestro

    See Maestro installation guide for other platforms.

  2. Build and install the app (development build requires Metro bundler):

    cd apps/expo
    # Terminal 1: Start Metro bundler
    yarn start
    
    # Terminal 2: Build and install app
    yarn ios  # or yarn android

Run tests:

# From root directory
yarn test:e2e:mobile

# From apps/expo directory
cd apps/expo
yarn test:e2e

# List available devices
yarn test:e2e:device:list

# Run a specific test file
maestro test .maestro/navigation/home-screen.yaml

Important: For development builds, ensure Metro bundler is running before executing Maestro tests. Also make sure to run your web and supabase instance to avoir network errors.

Documentation: See apps/expo/.maestro/README.md for detailed Maestro testing guide.

Database Tests

pgTAP-based tests for database schema, security, and functionality.

Location: supabase/tests/database/

Coverage:

  • Schema structure (tables, columns, types, constraints)
  • Row Level Security (RLS) policies
  • Database triggers
  • Database functions

Run tests:

# From root
yarn test:db

# Or directly
supabase test db

Prerequisites:

  • Supabase CLI must be installed
  • Local Supabase must be running (yarn supabase:start)

Documentation: See supabase/tests/README.md for detailed database testing guide.

API/Integration Tests

Vitest-based tests for tRPC procedures and API endpoints.

Location: packages/api/src/__tests__/

Coverage:

  • tRPC procedures (hello, userList, userById, userCreate, testAuth)
  • Authentication flows
  • Error handling
  • API integration

Run tests:

# From root
yarn test:api

# From packages/api directory
cd packages/api
yarn test

# Watch mode
yarn test:watch

# Interactive UI
yarn test:ui

# Coverage report
yarn test:coverage

Documentation: See packages/api/README_TESTING.md for detailed API testing guide.

Running All Tests

Run all tests (database, API, and E2E) from the root:

# Run all tests (database, API, and web E2E)
yarn test

# Watch mode
yarn test:watch

# Coverage report
yarn test:coverage

# Mobile E2E tests (from apps/expo directory)
cd apps/expo
yarn test:e2e

Test Configuration

  • Web E2E Tests: Configured in apps/next/playwright.config.ts
  • Mobile E2E Tests: Configured in apps/expo/.maestro/config.yaml
  • Database Tests: Uses pgTAP via Supabase CLI
  • API Tests: Configured in packages/api/vitest.config.ts

Quick Start

  1. Install dependencies:

    yarn install
  2. Start Supabase (for database and API tests):

    yarn supabase:start
  3. Run tests:

    # Database tests
    yarn test:db
    
    # API tests
    yarn test:api
    
    # Web E2E tests (requires Next.js dev server)
    yarn web  # In separate terminal
    yarn test:e2e:web  # In another terminal
    
    # Mobile E2E tests (requires Metro bundler and app installed)
    cd apps/expo
    yarn start  # Terminal 1: Start Metro
    yarn ios  # Terminal 2: Build and install app
    yarn test:e2e  # Terminal 3: Run Maestro tests

Additional Resources

πŸ†• Add new dependencies

Pure JS dependencies

If you're installing a JavaScript-only dependency that will be used across platforms, install it in packages/app:

cd packages/app
yarn add date-fns
cd ../..
yarn

Native dependencies

If you're installing a library with any native code, you must install it in apps/expo:

cd apps/expo
yarn add react-native-reanimated
cd ../..
yarn

You can also install the native library inside of packages/app if you want to get autoimport for that package inside of the app folder. However, you need to be careful and install the exact same version in both packages. If the versions mismatch at all, you'll potentially get terrible bugs. This is a classic monorepo issue.

To check for and fix version mismatches, use the check-deps command:

# Check for version mismatches
yarn check-deps

# Automatically fix version mismatches
yarn check-deps:fix

Always run yarn check-deps after installing dependencies to ensure all packages are using compatible versions.

πŸ›  Development Commands

# Install dependencies
yarn install

# Start Next.js dev server (loads .env.local automatically)
yarn web

# Start Expo dev server (loads .env automatically)
yarn native

# Start Storybook
yarn storybook:web      # Web Storybook (port 6006)
yarn storybook:native  # React Native Storybook (port 7007)

# Testing
yarn test              # Run all tests (database, API, web E2E)
yarn test:db           # Run database tests (pgTAP)
yarn test:api          # Run API/integration tests (Vitest)
yarn test:e2e:web      # Run web end-to-end tests (Playwright)
yarn test:watch        # Watch mode for all tests
yarn test:coverage     # Generate coverage report

yarn test:e2e:mobile    # Run mobile end-to-end tests (Maestro)

# Run linter
yarn lint

# Fix linting issues
yarn lint:fix

# Format code
yarn format

# EAS commands (from apps/expo directory)
cd apps/expo
npm run eas:build:android      # Build for Android
npm run eas:build:ios          # Build for iOS
npm run eas:submit:android     # Submit Android build
npm run eas:submit:ios         # Submit iOS build
npm run eas:update             # Publish OTA update

# Lingui commands
yarn lingui:extract      # Extract translatable messages from code
yarn lingui:translate   # Translate messages using AI (requires OPENAI_API_KEY)
yarn lingui:compile     # Compile translations for runtime use

# Supabase commands
yarn supabase:start      # Start local Supabase
yarn supabase:stop       # Stop local Supabase
yarn supabase:status     # Show connection details
yarn supabase:reset      # Reset database and run migrations
yarn supabase:logs       # View logs

# Dependency management
yarn check-deps          # Check for version mismatches across packages
yarn check-deps:fix      # Automatically fix version mismatches

Environment Variables in Scripts

Next.js:

  • Automatically loads .env.development when NODE_ENV=development (default for yarn dev)
  • Automatically loads .env.production when NODE_ENV=production (default for yarn build and yarn start)
  • Always loads .env.local last (highest priority, gitignored)
  • No dotenv-cli needed - Next.js handles this natively

Expo:

  • Uses scripts/load-env.js helper to load environment files based on NODE_ENV
  • Loads .env.development when NODE_ENV=development (default for yarn start, yarn ios, yarn android)
  • Loads .env.production when NODE_ENV=production (for yarn build:ios, yarn build:android)
  • Always loads .env.local last (highest priority, gitignored)

All yarn commands within each app directory automatically load the appropriate environment files based on NODE_ENV, so you don't need to manually source or export environment variables.

πŸ“š Documentation

πŸ“ License

This template is available as open source under the terms of the MIT License.

🀝 Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

⚠️ Important Notes

  • Review and customize supabase/seed.sql before deploying to production
  • Update all hardcoded URLs and API endpoints in your codebase
  • Set up proper environment variables for all environments
  • Configure Sentry for production error tracking
  • Set up proper database backups in Supabase
  • Review security settings in Supabase dashboard

πŸ†˜ Troubleshooting

Supabase local setup issues

If you encounter issues with local Supabase:

# Reset everything
yarn supabase:stop
docker system prune -a --volumes
yarn supabase:start

Port conflicts

If ports 3000, 54321, 54322, or 54323 are in use, you can:

  • Change ports in respective config files
  • Stop the conflicting services

Build issues

Clear caches and rebuild:

# Clear Turbo cache
rm -rf .turbo

# Clear Next.js cache
rm -rf apps/next/.next

# Reinstall dependencies
rm -rf node_modules apps/*/node_modules packages/*/node_modules
yarn install

πŸ—Ί Roadmap

Future enhancements planned for this template:

CI/CD Integration

  • GitHub Actions workflows for automated:
    • Linting and code quality checks
    • Running test suites (database, API, E2E)
    • Automated deployments to Vercel and EAS
    • Dependency security scanning
    • Build verification across all packages

Analytics/Telemetry

  • Optional integration with analytics platforms:
    • PostHog - Product analytics and feature flags
    • Amplitude - User behavior analytics
    • Configurable opt-in/opt-out for privacy compliance

Docs Automation

  • Developer documentation integration:
    • Docusaurus or Mintlify integration
    • Automated API documentation from tRPC routes
    • Component documentation from Storybook
    • Automated deployment of docs site

Performance Profiling

  • Built-in performance monitoring and profiling:
    • Web Vitals tracking
    • React Native performance profiling
    • Bundle size analysis
    • Performance regression detection

Package Version Sync Tooling

  • Monorepo version management:
    • Changesets integration for versioning
    • Automated changelog generation
    • Coordinated package releases
    • Dependency version synchronization

Template Customization CLI

  • Interactive CLI tool to customize the template:
    • Linter/Formatter options: Choose between Biome, ESLint/Prettier, or other tools
    • Error tracking: Optionally include or exclude Sentry
    • Authentication: Choose between Supabase Auth, Better Auth, or other providers
    • Database: Select Supabase, regular PostgreSQL, or other database solutions
    • Additional features: Selectively add Storybook, testing frameworks, etc.

Releases

No releases published

Sponsor this project

Packages

No packages published