Version: 1.0 · Last Updated: 2026-02-08
Build, deployment, and CI/CD pipeline specification for the ObjectStack Mobile client.
- Build System
- Environment Configuration
- Development Workflow
- EAS Build
- OTA Updates
- App Store Deployment
- CI/CD Pipeline
- Versioning Strategy
- Release Process
The app uses Expo's managed workflow, which means:
- No direct access to native
ios/orandroid/directories - Native modules are handled by Expo SDK and EAS Build
- Configuration is centralized in
app.config.tsandeas.json
| Tool | Purpose |
|---|---|
| Metro | JavaScript bundler (configured in metro.config.js) |
| Babel | Transpilation (configured in babel.config.js) |
| TypeScript | Type checking (tsconfig.json) |
| NativeWind | CSS-to-RN style compilation |
| EAS Build | Cloud-based native builds |
| EAS Update | Over-the-air JavaScript updates |
# Install dependencies
pnpm install
# Start development server
pnpm start
# Start on specific platform
pnpm start --ios
pnpm start --android
pnpm start --web
# Type check
npx tsc --noEmit
# Lint
npx eslint . --ext .ts,.tsx
# Format
npx prettier --write "**/*.{ts,tsx,js,json}"
# Test
pnpm test| Variable | Default | Description |
|---|---|---|
EXPO_PUBLIC_API_URL |
http://localhost:3000 |
ObjectStack server URL |
EXPO_PUBLIC_APP_SCHEME |
objectstack |
Deep link URL scheme |
| File | Purpose |
|---|---|
app.config.ts |
Expo app configuration (dynamic) |
app.json |
Expo base configuration (static) |
eas.json |
EAS Build/Update profiles |
tsconfig.json |
TypeScript compiler options |
tailwind.config.js |
Tailwind CSS configuration |
babel.config.js |
Babel plugins and presets |
metro.config.js |
Metro bundler configuration |
.eslintrc.js |
ESLint rules |
.prettierrc |
Prettier formatting rules |
.env.example |
Environment variable template |
// app.config.ts
export default ({ config }: ConfigContext): ExpoConfig => ({
name: "ObjectStack Mobile",
slug: "objectstack-mobile",
version: "1.0.0",
orientation: "portrait",
scheme: process.env.EXPO_PUBLIC_APP_SCHEME ?? "objectstack",
userInterfaceStyle: "automatic",
newArchEnabled: true,
ios: {
supportsTablet: true,
bundleIdentifier: "com.objectstack.mobile",
},
android: {
adaptiveIcon: { /* ... */ },
edgeToEdgeEnabled: true,
package: "com.objectstack.mobile",
},
plugins: ["expo-router"],
extra: {
apiUrl: process.env.EXPO_PUBLIC_API_URL ?? "http://localhost:3000",
},
});// eas.json
{
"cli": { "version": ">= 3.0.0" },
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal",
"env": {
"EXPO_PUBLIC_API_URL": "https://staging.objectstack.com"
}
},
"production": {
"env": {
"EXPO_PUBLIC_API_URL": "https://api.objectstack.com"
}
}
},
"submit": {
"production": {
"ios": { "appleId": "...", "ascAppId": "..." },
"android": { "serviceAccountKeyPath": "..." }
}
}
}1. Clone repository
2. pnpm install
3. Copy .env.example → .env.local
4. Configure EXPO_PUBLIC_API_URL
5. pnpm start
6. Open on device/simulator
# Start Expo dev server
npx expo start
# Options:
# Press 'i' for iOS simulator
# Press 'a' for Android emulator
# Press 'w' for web browser
# Scan QR code for Expo Go (development only)For native module development, create a development build:
# iOS development build
eas build --platform ios --profile development
# Android development build
eas build --platform android --profile development| Profile | Purpose | Distribution |
|---|---|---|
development |
Dev builds with dev client | Internal (team) |
preview |
Staging builds for QA | Internal (TestFlight / APK) |
production |
Release builds for stores | Store submission |
# Development build (with dev client)
eas build --platform ios --profile development
eas build --platform android --profile development
# Preview build (staging)
eas build --platform ios --profile preview
eas build --platform android --profile preview
# Production build
eas build --platform ios --profile production
eas build --platform android --profile production
# Build both platforms
eas build --platform all --profile productionSource Code
↓
EAS Build (Cloud)
├── Install dependencies (pnpm install)
├── Run prebuild hooks
├── Generate native projects
├── Compile native code (Xcode / Gradle)
└── Sign & package
↓
Build Artifact
├── iOS: .ipa file
└── Android: .aab / .apk file
Over-the-air updates allow pushing JavaScript changes without a new app store release:
# Push update to preview channel
eas update --branch preview --message "Fix list rendering"
# Push update to production channel
eas update --branch production --message "v1.0.1 hotfix"
# Check update status
eas update:list| Change Type | Deployment |
|---|---|
| JS/TS code changes | OTA update (instant) |
| New native modules | Full store build required |
| Expo SDK upgrade | Full store build required |
| Config changes | Full store build required |
| Asset changes | OTA update |
| Channel | Branch | Usage |
|---|---|---|
development |
develop |
Development builds |
preview |
staging |
QA / staging builds |
production |
main |
Production app |
# Submit to App Store Connect
eas submit --platform ios --profile production
# Or submit a specific build
eas submit --platform ios --id <build-id>Requirements:
- Apple Developer account
- App Store Connect app record
- Screenshots and metadata
- Privacy policy URL
- App review guidelines compliance
# Submit to Google Play Console
eas submit --platform android --profile production
# Or submit a specific build
eas submit --platform android --id <build-id>Requirements:
- Google Play Developer account
- Play Console app listing
- Service account key for automated submission
- Privacy policy URL
- Content rating questionnaire
Push / PR
↓
┌───────────────────────────┐
│ Lint & Type Check │
│ npx tsc --noEmit │
│ npx eslint . --ext .ts,.tsx│
└─────────────┬─────────────┘
↓
┌───────────────────────────┐
│ Unit & Integration Tests │
│ pnpm test -- --coverage │
└─────────────┬─────────────┘
↓
┌───────────────────────────┐
│ Preview Build (on merge) │
│ eas build --profile preview│
└─────────────┬─────────────┘
↓
┌───────────────────────────┐
│ OTA Update (on tag) │
│ eas update --branch prod │
└───────────────────────────┘
# .github/workflows/pr-check.yml
name: PR Check
on: pull_request
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "pnpm"
- run: pnpm install
- run: npx tsc --noEmit
- run: npx eslint . --ext .ts,.tsx
- run: pnpm test -- --coverage --ci# .github/workflows/build.yml
name: Build
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "pnpm"
- uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- run: pnpm install
- run: eas build --platform all --profile preview --non-interactive# .github/workflows/update.yml
name: OTA Update
on:
push:
tags: ["v*"]
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "pnpm"
- uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- run: pnpm install
- run: eas update --branch production --message "${{ github.ref_name }}"MAJOR.MINOR.PATCH
│ │ └── Bug fixes, patches
│ └──────── New features (backward compatible)
└─────────────── Breaking changes
# Patch (bug fix): 1.0.0 → 1.0.1
npm version patch
# Minor (feature): 1.0.0 → 1.1.0
npm version minor
# Major (breaking): 1.0.0 → 2.0.0
npm version major| Version | Content | Status |
|---|---|---|
v0.4-alpha |
Phase 4A (rendering, files, charts) | In Progress |
v0.5-alpha |
Phase 5A (i18n, performance, tests) | Planned |
v0.6-beta |
Phase 4B (permissions, workflows, realtime) | Blocked (SDK) |
v0.7-beta |
Phase 5B (AI, server i18n, SDK hooks) | Blocked (SDK) |
v1.0-GA |
Phase 6 (monitoring, final optimization) | Planned |
- All PR checks passing (lint, type check, tests)
- No critical/high severity bugs open
- Dependencies updated and vulnerability-free
- Version number bumped in
package.jsonandapp.config.ts - CHANGELOG updated
- Screenshots updated (if UI changes)
1. Create release branch: release/v1.x.x
2. Run full test suite: pnpm test -- --coverage
3. Bump version: pnpm version minor
4. Build production: eas build --platform all --profile production
5. Test builds on devices
6. Submit to stores: eas submit --platform all --profile production
7. Tag release: git tag v1.x.x
8. Merge to main
9. Create GitHub release with changelog
10. Monitor crash reports (Sentry)
| Scenario | Action |
|---|---|
| JS bug | Push OTA update fix via eas update |
| Native crash | Submit hotfix build to stores |
| Critical security | Emergency OTA update + store submission |
| Store rejection | Fix issues, resubmit |
This document covers the deployment and CI/CD strategy. See CONTRIBUTING.md for development workflow and TESTING.md for testing guidelines.