Courses/Grit Mobile/Your First Mobile App
Course 1 of 5~30 min12 challenges

Your First Mobile App

In this course, you will scaffold a mobile project with Grit, set up your development environment, run the app on a device or emulator, and understand how the Go API and Expo app work together. By the end, you will have a working mobile app connected to a live backend.


What is Mobile Development with Grit?

Grit scaffolds a monorepo that contains both a Go API and an Expo React Native app. You write React components that compile to native iOS and Android code. The Go API is exactly the same as in web projects — same routes, same services, same database. Only the frontend is different.

React Native: A framework by Meta that lets you build native mobile apps using React and JavaScript. Instead of rendering to the browser DOM, React Native renders to real native iOS and Android views. You write one codebase, and it runs on both platforms.
Expo: A platform built on top of React Native that handles the complexity of native iOS and Android development. Expo provides dev tools, build services, and over-the-air updates so you can focus on writing React code instead of configuring Xcode and Android Studio.
  • The Go API runs on your server — same as a web project
  • The Expo app runs on a phone (or emulator) and calls the API over HTTP
  • Shared types keep the API and app in sync
  • One codebase, two platforms (iOS + Android)

Prerequisites

You need the same tools as a web project, plus a few mobile-specific ones:

ToolWhat it doesCheck
Go 1.21+Runs the backend APIgo version
Node.js 18+Runs the Expo dev servernode --version
pnpm 8+Installs JavaScript packagespnpm --version
DockerRuns PostgreSQL, Redis, MinIOdocker --version
Expo Go appRuns your app on a physical phoneApp Store / Play Store
Emulator / Simulator: Software that mimics a phone on your computer. On macOS, the iOS Simulator comes with Xcode. On any OS, the Android Emulator comes with Android Studio. If you don't want to install either, you can use the Expo Go app on your physical phone instead.
The fastest way to get started is to install the Expo Go app on your phone. No emulator setup required — just scan a QR code to run the app on your device.
1

Challenge: Install Expo Go

Install the Expo Go app on your phone from the App Store (iOS) or Play Store (Android). Open it and confirm it launches successfully.

2

Challenge: Check Your Tools

Open your terminal and run all four check commands from the table above. Confirm each tool is installed and returns a version number.

Scaffold a Mobile Project

Use the --mobile flag to scaffold a project with an Expo app instead of (or alongside) a web frontend:

grit new fitness --mobile

This creates a monorepo with the following structure:

fitness/
├── apps/
│   ├── api/           ← Go backend (same as web)
│   └── expo/          ← React Native app (Expo)
├── packages/
│   └── shared/        ← Shared types + schemas
├── docker-compose.yml
└── turbo.json

The apps/api/ directory is identical to a web project — same Go code, same routes, same services. The only difference is apps/expo/ replacingapps/web/.

Expo Router: File-based routing for React Native. Just like Next.js App Router maps files to web pages, Expo Router maps files to mobile screens. Files in the app/ directory become navigable screens in your app.
3

Challenge: Scaffold a Mobile Project

Run grit new fitness --mobile. Explore the folder structure. How many directories are inside apps/? What's inside packages/shared/?

Start the API

The API is a standard Grit Go backend. Start the infrastructure services first, then run the API server:

# Start PostgreSQL, Redis, MinIO
docker compose up -d

# Run the Go API
cd apps/api && go run cmd/server/main.go

The API will start on http://localhost:8080. You can verify it's running by opening that URL in your browser — you should see a JSON health check response.

The mobile app connects to this exact same API. There is no special "mobile backend" — the Go API serves both web and mobile clients identically.
4

Challenge: Start the API

Start the infrastructure with docker compose up -d, then run the API. Open http://localhost:8080 in your browser. What JSON response do you see?

Start Expo

With the API running, open a new terminal and start the Expo dev server:

cd apps/expo && npx expo start

Expo will display a QR code in the terminal. You have three options:

  • Physical phone: Scan the QR code with Expo Go (Android) or your camera app (iOS)
  • iOS Simulator: Press i in the terminal (macOS only, requires Xcode)
  • Android Emulator: Press a in the terminal (requires Android Studio)
Hot reloading works automatically. When you save a file, the app updates instantly on your device or emulator — no need to restart.
5

Challenge: Run Expo

Start Expo and open the app on your phone or emulator. You should see the default home screen. Try editing apps/expo/app/index.tsx — does the change appear immediately?

Project Structure

The Expo app follows the same conventions as a Next.js project. Here's what's insideapps/expo/:

apps/expo/
├── app/                 ← Screens (Expo Router)
│   ├── _layout.tsx      ← Root layout (wraps all screens)
│   ├── index.tsx        ← Home screen
│   ├── login.tsx        ← Login screen
│   ├── register.tsx     ← Register screen
│   └── (tabs)/          ← Tab navigation group
│       ├── _layout.tsx  ← Tab bar configuration
│       ├── index.tsx    ← Home tab
│       └── profile.tsx  ← Profile tab
├── components/          ← Reusable UI components
├── hooks/               ← Custom hooks (useAuth, etc.)
├── lib/                 ← API client, utilities
└── package.json

Key Expo Router conventions:

  • _layout.tsx — Wraps child screens. Defines navigation structure (stack, tabs).
  • index.tsx — The default screen for a directory (like / in a URL).
  • (tabs)/ — A route group. The parentheses mean it doesn't appear in the URL.
  • Any .tsx file in app/ becomes a screen automatically.
6

Challenge: Explore the Structure

Open apps/expo/app/. List all the files. Which file is the root layout? What does the (tabs)/ directory contain?

7

Challenge: Understand the Layout

Open apps/expo/app/_layout.tsx. What component does it use to wrap the app? Does it set up a Stack navigator or a Tab navigator at the root level?

Shared Types

The packages/shared/ directory is used by both the Go API and the Expo app. It contains Zod schemas and TypeScript types that keep the frontend and backend in sync.

packages/shared/
├── types/
│   ├── user.ts       ← User type + schemas
│   ├── auth.ts       ← Login/register schemas
│   └── api.ts        ← API response types
├── schemas/
│   └── index.ts      ← Zod validation schemas
└── constants/
    └── routes.ts     ← API route constants

When you use grit generate resource to add a new API resource, the TypeScript types are automatically generated in packages/shared/. Your mobile app gets them for free — no manual syncing required.

8

Challenge: Explore Shared Types

Open packages/shared/types/. What types are defined? Compare them to what the API returns at /api/auth/login. Are they the same?

The API Client

The mobile app calls the Go API using a configured HTTP client. Here's how a typical API call looks:

// lib/api.ts
const API_URL = "http://localhost:8080"

export async function login(email: string, password: string) {
  const response = await fetch(API_URL + "/api/auth/login", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email, password }),
  })
  return response.json()
}
On a physical device, localhost won't work — your phone can't reach your computer's localhost. You need to use your computer's local IP address instead (e.g., http://192.168.1.42:8080). Expo shows your local IP in the terminal output when you run npx expo start.
On Android Emulator, you can use http://10.0.2.2:8080 to reach the host machine's localhost. This is a special alias built into the Android emulator.
9

Challenge: Find the API Client

Find the API client file in the Expo app (check lib/ or hooks/). What base URL does it use? What headers does it set?

10

Challenge: Test the Connection

With the API running, open the mobile app and try to register a new user. Check the API logs in your terminal — do you see the incoming request?

Summary

Here's what you learned in this course:

  • Grit scaffolds a monorepo with a Go API and an Expo React Native app
  • The Go API is identical to web projects — same code, same routes
  • Expo Router provides file-based navigation (like Next.js for mobile)
  • Shared types keep the API and mobile app in sync
  • The API client connects the mobile app to the Go backend over HTTP
11

Challenge: Register a User

Using the mobile app, register a new user with an email and password. Then log in with those credentials. Does the app navigate to the home screen?

12

Challenge: End-to-End Test

Create a blog post via the API docs at http://localhost:8080/swagger. Then open the mobile app and navigate to the content screen. Does the new post appear? Pull down to refresh if needed.