Monorepo structure
The repository is organized into two main directories:All apps in
apps/* and packages in packages/* are defined as workspaces in the root package.json.Workspace configuration
The monorepo uses Bun workspaces for dependency management and script execution. The rootpackage.json defines the workspace:
package.json
Running workspace commands
You can run commands for specific apps from the monorepo root using the--filter flag:
package.json provides convenient aliases:
Applications
Each app is a complete, deployable application with its own build configuration and dependencies.@workspace/spa
Framework
React 19
Routing
TanStack Router
Build Tool
Vite 7
Port
3001
- React 19 with the new React Compiler
- TanStack Router for type-safe routing
- TanStack Query for data fetching and caching
- TanStack Form for form management
- Vite for fast development and optimized builds
- Tailwind CSS 4 for styling
- React Aria Components for accessible UI
- PWA support with Vite PWA plugin
- OpenTelemetry for observability (metrics and traces)
- Playwright for E2E testing
apps/spa/package.json
@workspace/web
Framework
Next.js 16
Database
PostgreSQL + Drizzle ORM
Auth
Better Auth
Port
3002
- Next.js 16 with App Router and React Server Components
- Better Auth for authentication
- Drizzle ORM for type-safe database queries
- PostgreSQL database
- TanStack Query for client-side data fetching
- React Hook Form with Zod validation
- Next Safe Action for type-safe server actions
- Tailwind CSS 4 for styling
- React Aria Components for accessible UI
- OpenTelemetry for observability (metrics, traces, and logs)
- Playwright for E2E testing
- Internationalization with next-intl
apps/web/package.json
@workspace/expo
Framework
React Native + Expo 53
Routing
Expo Router
UI
Tamagui
Testing
Maestro
- Expo 53 for managed React Native development
- Expo Router for file-based routing
- React Navigation for navigation primitives
- Tamagui for cross-platform UI components
- TanStack Query for data fetching
- React Hook Form with Zod validation
- MMKV for fast key-value storage
- Internationalization with i18next
- Maestro for E2E testing
- EAS Build for cloud builds
- EAS Update for over-the-air updates
apps/expo/package.json
Shared packages
Packages provide reusable code that all apps can consume.@workspace/core
The core package contains shared business logic, types, hooks, and utilities that work across both browser and mobile environments.Package structure
Package structure
packages/core/package.json
The core package uses peer dependencies to avoid duplication. Apps must install
ky, radashi, react, type-fest, and zod.@workspace/typescript-config
Shared TypeScript configuration that ensures consistent type checking across all apps and packages.apps/spa/tsconfig.json
Dependency management
The monorepo follows strict dependency management practices:Exact versions
Workspace dependencies
Internal packages use theworkspace:* protocol:
Shared dependencies
Common dependencies are installed at the workspace root when possible:Root dependencies
package.json.
Code organization
Each app follows a consistent directory structure:- SPA Structure
- Web Structure
- Expo Structure
Build and deployment
Each app has its own build and deployment strategy:SPA deployment
The SPA builds to static files that can be deployed to any static hosting:Web deployment
The Next.js app can be deployed to Vercel or any Node.js hosting:Expo deployment
Expo uses EAS Build for cloud builds and EAS Update for OTA updates:Development tools
The monorepo includes shared tooling:Linting
ESLint with@antfu/eslint-config for consistent code style:
Type checking
TypeScript checking across all apps:Testing
- SPA & Web: Playwright for E2E tests
- Expo: Maestro for mobile E2E tests
Changesets
For versioning and changelog generation:Environment variables
Local environment files are the source of truth. Update deployment/CI environments when you change local files.
SPA & Web
Both apps use.env.dev and .env.prod files:
- Environment:
dev→ Secret:SPA_ENV_FILEwith.env.devcontent - Environment:
prod→ Secret:SPA_ENV_FILEwith.env.prodcontent
Expo
Expo uses EAS environment variables:Observability
The monorepo includes OpenTelemetry integration for production observability:Local development
Run the Grafana LGTM stack for local observability:- Prometheus for metrics
- Tempo for traces
- Loki for logs
- Pyroscope for profiling
- Grafana dashboard at http://localhost:3111
- Username:
admin - Password:
admin
Production
Both SPA and Web apps include OpenTelemetry instrumentation:- SPA: Browser metrics and traces
- Web: Server-side metrics, traces, and logs
Best practices
Shared code
Extract shared logic to
@workspace/core when used by 2+ appsType safety
Use TypeScript strictly with
strict: true and exactOptionalPropertyTypes: trueExact versions
Always use exact dependency versions for reproducible builds
Environment vars
Keep
.env files in sync between local and deploymentNext steps
SPA Guide
Explore the React SPA architecture
Web Guide
Learn about the Next.js app
Expo Guide
Build mobile apps with Expo
