Skip to main content
Quest Hunter’s tech stack is carefully chosen to enable rapid development, excellent performance, and seamless real-time experiences on mobile devices.

Core Technologies

React Native 0.81.5

Cross-platform mobile framework for iOS and Android using React

Expo SDK ~54

Development platform that simplifies React Native development

Convex 1.32

Real-time backend-as-a-service with TypeScript functions

Clerk Expo 2.19

Authentication and user management for mobile apps

Frontend Framework

React 19.1.0

Quest Hunter uses the latest React version, providing:
  • React Compiler optimizations - Automatic memoization
  • Improved hooks - Better performance and DX
  • Server Components compatibility - Future-proofing for RSC

Expo Framework

Expo provides managed infrastructure for React Native development:
PackageVersionPurpose
expo~54.0.33Core Expo SDK
expo-router~6.0.23File-based navigation
expo-dev-client~6.0.20Custom development builds
expo-maps~0.12.10Native map integration
expo-image~3.0.11Optimized image component
expo-image-picker~17.0.10Camera/gallery access
expo-haptics~15.0.8Tactile feedback
Expo Router enables file-based routing similar to Next.js, making navigation intuitive and type-safe.

Why Expo?

  1. Faster iteration - Over-the-air updates without app store approval
  2. Native modules - Pre-configured access to device features
  3. EAS Build - Cloud-based native compilation
  4. Development tools - Expo Go for instant testing

Backend Infrastructure

Convex - Real-time Backend

Version: 1.32.0 Convex replaces traditional backend infrastructure with TypeScript functions:
// Reactive query - automatically syncs
export const listRecommended = query({
  handler: async (ctx) => {
    const user = await requireUser(ctx);
    const quests = await ctx.db.query("quests").collect();
    return quests.filter(/* ... */);
  },
});

// Mutation - modifies data
export const start = mutation({
  handler: async (ctx, { questId }) => {
    const user = await requireUser(ctx);
    await ctx.db.insert("userQuests", {
      userId: user._id,
      questId,
      startedAt: Date.now(),
    });
  },
});

Key Features

Reactive Queries

Queries automatically re-run when underlying data changes, keeping all clients in sync

ACID Transactions

All mutations run in transactions, ensuring data consistency

TypeScript Native

Write backend code in TypeScript with full type inference

File Storage

Built-in file storage for images and documents

Why Convex?

  1. No backend boilerplate - Focus on business logic, not infrastructure
  2. Real-time by default - No WebSocket setup or polling logic
  3. Type-safe API - Generated types from schema to frontend
  4. Automatic scaling - Handles traffic spikes without configuration
  5. Integrated auth - Native support for Clerk JWT validation

Database Schema

Location: convex/schema.ts
defineSchema({
  quests: defineTable({...}),
  locations: defineTable({...})
    .index("by_quest", ["questId"])
    .index("by_quest_order", ["questId", "order"]),
  users: defineTable({...})
    .index("by_clerk_id", ["clerkId"]),
  userQuests: defineTable({...})
    .index("by_user", ["userId"])
    .index("by_user_and_quest", ["userId", "questId"]),
  userLocations: defineTable({...})
    .index("by_user_and_quest", ["userId", "questId"]),
});

Authentication

Clerk - User Management

Version: @clerk/clerk-expo 2.19.27 Clerk provides:
  • OAuth providers - Google, Apple, GitHub integration
  • Session management - Secure token handling
  • User profiles - Avatar, name, email management
  • Webhooks - User event synchronization

Integration Pattern

// app/_layout.tsx
<ClerkProvider
  publishableKey={process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY}
  tokenCache={tokenCache} // Uses expo-secure-store
>
  <ConvexProviderWithClerk client={convex} useAuth={useAuth}>
    {/* App content */}
  </ConvexProviderWithClerk>
</ClerkProvider>

Token Caching

Clerk tokens are cached in expo-secure-store, providing:
  • Hardware-backed encryption on supported devices
  • Persistent sessions across app restarts
  • Automatic token refresh before expiration

Why Clerk?

  1. Native mobile support - Built for React Native
  2. Convex integration - Official support for JWT validation
  3. User experience - Pre-built auth UI components
  4. Compliance - GDPR, SOC 2 compliant

Styling & UI

NativeWind - Tailwind for React Native

Version: 4.2.2 NativeWind brings Tailwind CSS to React Native:
// Works exactly like web Tailwind
<View className="flex-1 bg-background p-4">
  <Text className="text-xl font-bold text-foreground">
    Quest Title
  </Text>
</View>

Configuration

Location: tailwind.config.js
module.exports = {
  content: ["./app/**/*.{ts,tsx}", "./components/**/*.{ts,tsx}"],
  presets: [require("nativewind/preset")],
  theme: {
    extend: {
      colors: {
        // Custom color system
        border: "hsl(var(--border))",
        background: "hsl(var(--background))",
        // ...
      },
    },
  },
};

RN Primitives - Accessible Components

Base component library providing:
PackagePurpose
@rn-primitives/alert-dialogModal dialogs
@rn-primitives/labelForm labels
@rn-primitives/portalRender outside tree
@rn-primitives/separatorDivider lines
@rn-primitives/tabsTab navigation
@rn-primitives/slotComponent composition
These primitives ensure accessibility features like screen reader support and keyboard navigation.

Utility Libraries

  • class-variance-authority (0.7.1) - Component variant management
  • clsx (2.1.1) - Conditional className joining
  • tailwind-merge (3.5.0) - Merge Tailwind classes without conflicts
  • tailwindcss-animate (1.0.7) - Animation utilities

Expo Router + React Navigation

Expo Router is built on React Navigation:
PackageVersionPurpose
expo-router~6.0.23File-based routing
@react-navigation/native^7.1.8Navigation core
@react-navigation/bottom-tabs^7.4.0Tab bar
react-native-screens~4.16.0Native screen optimization

Router Structure

app/
  _layout.tsx              # Root layout
  (auth)/                  # Auth group (unprotected)
    sign-in.tsx
  (tabs)/                  # Tab group (protected)
    (quests)/
      index.tsx            # /quests
      [id]/
        index.tsx          # /quests/:id
        location/
          [locationId].tsx # /quests/:id/location/:locationId
Parentheses in folder names create route groups that share layouts but don’t add URL segments.

Animation & Gestures

Reanimated - Performant Animations

Version: react-native-reanimated 4.2.2 Provides 60 FPS animations running on the native thread:
const opacity = useSharedValue(0);
const animatedStyle = useAnimatedStyle(() => ({
  opacity: withTiming(opacity.value, { duration: 300 }),
}));

Gesture Handler

Version: react-native-gesture-handler ~2.28.0 Native gesture recognition for swipes, pinches, and drags.

Developer Experience

TypeScript

Version: 5.9.2 Strict TypeScript configuration ensures type safety:
// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "skipLibCheck": true,
    "moduleResolution": "bundler"
  }
}

Code Quality Tools

ToolVersionPurpose
eslint9.25.0JavaScript linting
eslint-config-expo~10.0.0Expo-specific rules
prettier3.8.1Code formatting
prettier-plugin-tailwindcss0.5.11Sort Tailwind classes
husky9.1.7Git hooks
commitlint20.4.2Commit message linting

Package Management

Bun 1.3.9 is used instead of npm/yarn:
  • Faster installs - 10-100x faster than npm
  • Built-in scripts - Task runner included
  • TypeScript native - No transpilation needed
  • Compatible - Works with npm packages
The project requires Node.js >=24.14.0 as specified in package.json engines, but uses Bun for package management.

Build & Deployment

Expo Application Services (EAS)

Configuration: eas.json
{
  "build": {
    "development": { /* dev builds */ },
    "preview": { /* internal testing */ },
    "production": { /* app store builds */ }
  }
}

Development Scripts

{
  "dev": "mprocs \"bun start\" \"bun convex:dev\"",
  "start": "expo start",
  "convex:dev": "convex dev",
  "ios": "expo run:ios",
  "android": "expo run:android"
}

Environment Configuration

Required environment variables (.env.example):
EXPO_PUBLIC_CONVEX_URL=       # Convex deployment URL
EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=  # Clerk public key
CLERK_JWT_ISSUER_DOMAIN=      # Clerk JWT issuer

Technology Decision Summary

CategoryChoiceWhy?
Mobile FrameworkReact Native + ExpoCross-platform, fast iteration, rich ecosystem
BackendConvexReal-time sync, no infrastructure, TypeScript-native
AuthClerkMobile-first, Convex integration, excellent UX
StylingNativeWindFamiliar DX, utility-first, cross-platform
NavigationExpo RouterType-safe, file-based, familiar pattern
LanguageTypeScriptType safety, better DX, catches bugs early
Package ManagerBunSpeed, TypeScript support, modern tooling
This stack enables a small team to build and iterate quickly while maintaining production-quality code and user experience.

Build docs developers (and LLMs) love