Platform Strategy
Why This Matters
Your web app works. Users are testing it. Now someone asks: “Is there a mobile app?”
This is one of the most consequential decisions you’ll make as a product builder. Go mobile too early and you waste months. Wait too long and you miss a growth window. Choose the wrong approach and you’re stuck maintaining multiple codebases forever.
This chapter teaches you how to think about platform strategy, when mobile actually makes sense, and the technical options for getting there, from PWAs to native apps.
Part 1: The Strategy
The Platform Decision Framework
Before jumping to solutions, ask these questions:
| Question | If Yes | If No |
|---|---|---|
| Do users need this when away from computers? | Consider mobile | Web is fine |
| Does it need device hardware (camera, GPS, sensors)? | Consider mobile | Web is fine |
| Is your core user flow < 30 seconds? | Mobile-friendly matters | Desktop-first okay |
| Do competitors have apps? | Understand why | May not need one |
| Will users install another app? | Maybe mobile | Probably web |
The key insight: Most products don’t need native apps. Web works for most B2B tools, productivity apps, and content platforms. Mobile matters most for consumer apps with frequent, brief interactions.
Web vs. Mobile: The Real Tradeoffs
Distribution
Web advantages: - Instant access via URL (no installation) - SEO brings organic traffic - Updates deploy instantly - One codebase for all users - Works on any device with a browser
Mobile (App Store) advantages: - Discovery through app stores - Home screen presence - Push notification reliability - “There’s an app for that” legitimacy - Better retention for installed apps
The hard truth: App store discovery is brutal. Unless you’re in a category people actively search (fitness, dating, games), organic app store traffic is minimal. You’ll need to drive users there yourself, which means you need web anyway.
Development & Maintenance
| Factor | Web Only | Web + Mobile |
|---|---|---|
| Initial build time | 1x | 2-3x |
| Ongoing maintenance | 1 codebase | 2-3 codebases |
| Feature parity | N/A | Constant challenge |
| Team size needed | Smaller | Larger |
| Bug surface area | Smaller | Much larger |
The hidden cost: Mobile isn’t just building once. It’s maintaining multiple platforms forever. Every feature ships twice (or three times). Every bug exists in multiple places.
User Behavior
Mobile makes sense when: - Usage is frequent (daily+) and brief (< 2 minutes) - Location matters (maps, local search) - Camera/photos are core to the experience - Offline access is important - Push notifications drive engagement
Web makes more sense when: - Tasks require focus (30+ minutes) - Heavy text input is common - Users are at desks (B2B, productivity) - File handling is important - SEO is a growth channel
The Platform Spectrum
You don’t have to choose between “web only” and “native app.” There’s a spectrum:
Web → Responsive Web → PWA → Capacitor/Ionic → React Native → Native
<---------------- Easier ----------------->
<---------------- More "native" ---------->
| Approach | Effort | Native Feel | Store Distribution |
|---|---|---|---|
| Responsive Web | Low | Low | No |
| PWA | Medium | Medium | Limited |
| Capacitor | Medium | Medium-High | Yes |
| React Native | High | High | Yes |
| Native (Swift/Kotlin) | Highest | Highest | Yes |
For most startups, the sweet spot is Responsive Web → PWA → Capacitor progression:
- Start responsive: Mobile-friendly web
- Add PWA: Installable, offline-capable
- Wrap with Capacitor: Ship to app stores when needed
Progressive Web Apps (PWAs)
PWAs are web apps with superpowers. They can: - Be installed on home screens - Work offline - Send push notifications (mostly) - Feel like native apps
PWA requirements: - HTTPS (required) - Service worker (for offline/caching) - Web app manifest (metadata for installation)
PWA limitations: - iOS Safari support is limited - Push notifications restricted on iOS - Some native APIs unavailable - Can’t be listed in app stores (usually)
When PWA is enough: - Internal tools - B2B products - Content-heavy apps - Products where installation isn’t critical
Capacitor: Web to Native
Capacitor (by the Ionic team) wraps your web app in a native container. You get: - Full app store distribution - Access to native device APIs - One codebase, multiple platforms - Keep your existing React/Vue/Angular code
How it works:
Your Web App (React, etc.)
↓
Capacitor
↓
iOS App Android App Web App
Capacitor is ideal when: - You have a working web app - You need app store presence - Native API access is important - You want to maintain one codebase
Capacitor limitations: - Performance-intensive apps may struggle - Complex animations can feel non-native - Some native APIs need custom plugins - UI doesn’t automatically match platform conventions
When to Go Fully Native
Sometimes web-based approaches aren’t enough:
Consider native (Swift, Kotlin) when: - Performance is critical (games, video, AR) - Complex gestures and animations are core - Deep OS integration is required - Your competitors set native expectations - You have the team and resources
Consider React Native when: - You need native performance - Your team knows JavaScript/React - You want shared logic but native UI - Instagram/Facebook-level apps
The honest advice: If you’re asking “should I go native?”, the answer is probably no. Native development requires specialized skills, more time, and larger teams. Start simpler, validate, then upgrade if needed.
Making the Decision
The Startup Path
Phase 1: Validate (Week 1-8) - Build responsive web - Focus on core value proposition - Test with users
Phase 2: Grow (Week 8-16) - Add PWA capabilities - Improve mobile experience - Monitor usage patterns
Phase 3: Expand (If needed) - Wrap with Capacitor for app stores - Or stay web-only if it’s working
Decision Matrix
| Your Situation | Recommendation |
|---|---|
| Pre-product-market fit | Stay web only |
| B2B / productivity | Responsive web + PWA |
| Consumer, frequent use | PWA → Capacitor |
| Hardware-dependent | Capacitor or native |
| Gaming / media-heavy | Native or React Native |
Part 2: Building It
Making Your App Mobile-Responsive
Before anything else, your web app needs to work well on mobile screens.
Responsive CSS Basics
Use CSS media queries to adjust layouts:
/* Default (mobile-first) */
.container {
display: flex;
flex-direction: column;
padding: 1rem;
}
/* Tablet and up */
@media (min-width: 768px) {
.container {
flex-direction: row;
padding: 2rem;
}
}
/* Desktop */
@media (min-width: 1024px) {
.container {
max-width: 1200px;
margin: 0 auto;
}
}Tailwind Responsive Utilities
If you’re using Tailwind CSS, responsive design is built in:
<div className="flex flex-col md:flex-row lg:max-w-4xl">
<aside className="w-full md:w-64">Sidebar</aside>
<main className="flex-1">Content</main>
</div>Prefixes: sm: (640px), md: (768px), lg: (1024px), xl: (1280px)
Mobile UX Essentials
- Touch targets: Minimum 44×44px for buttons
- Font sizes: 16px minimum to prevent zoom on iOS
- Forms: Use appropriate input types (
type="email",type="tel") - Viewport: Always include
<meta name="viewport" content="width=device-width, initial-scale=1">
Setting Up a PWA
1. Create the Manifest
Create public/manifest.json:
{
"name": "My Product",
"short_name": "Product",
"description": "A brief description of your product",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#000000",
"icons": [
{
"src": "/icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}Link it in your HTML:
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#000000">2. Add a Service Worker
For Next.js, use the next-pwa package:
npm install next-pwaUpdate next.config.js:
const withPWA = require('next-pwa')({
dest: 'public',
disable: process.env.NODE_ENV === 'development'
});
module.exports = withPWA({
// Your other Next.js config
});3. Test Installation
- Deploy to HTTPS (Vercel handles this)
- Open in Chrome
- Look for install prompt or use DevTools → Application → Manifest
Capacitor Setup
Initialize Capacitor
npm install @capacitor/core @capacitor/cli
npx cap initThis creates capacitor.config.ts:
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.yourcompany.yourapp',
appName: 'Your App',
webDir: 'out', // or 'build' or '.next' depending on your setup
server: {
androidScheme: 'https'
}
};
export default config;Add Platforms
# Install platform packages
npm install @capacitor/ios @capacitor/android
# Add platforms
npx cap add ios
npx cap add androidBuild and Sync
# Build your web app first
npm run build
# Copy web assets to native projects
npx cap sync
# Open in native IDEs
npx cap open ios # Opens Xcode
npx cap open android # Opens Android StudioUsing Native APIs
Install Capacitor plugins for native features:
npm install @capacitor/camera @capacitor/filesystemUse them in your code:
import { Camera, CameraResultType } from '@capacitor/camera';
async function takePhoto() {
const photo = await Camera.getPhoto({
quality: 90,
resultType: CameraResultType.Uri
});
// photo.webPath contains the image
return photo.webPath;
}Claude Code: Hooks
Hooks are automated actions that run at specific points in your development workflow. They help maintain code quality without manual checks.
What Are Hooks?
Claude Code hooks are shell commands or scripts that run automatically when certain events happen:
- Pre-commit: Before code is committed
- Post-commit: After code is committed
- Pre-push: Before code is pushed
- File change: When specific files are modified
Setting Up Git Hooks with Husky
Husky is the standard way to manage Git hooks in JavaScript projects:
npm install -D husky
npx husky initThis creates .husky/ directory with hook files.
Pre-commit Hook Example
Create .husky/pre-commit:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Run linting
npm run lint
# Run type checking
npm run type-check
# Run tests
npm testNow these run automatically before every commit. If any fail, the commit is blocked.
Lint-Staged for Faster Checks
Running all checks on every file is slow. Lint-staged runs checks only on files being committed:
npm install -D lint-stagedAdd to package.json:
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{css,scss}": [
"prettier --write"
]
}
}Update .husky/pre-commit:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-stagedClaude Code Hook Configuration
Claude Code can also run hooks. Create .claude/hooks/ in your project:
mkdir -p .claude/hooksCreate .claude/hooks/pre-edit.sh:
#!/bin/bash
# Run before Claude edits files
# Ensure we're not editing protected files
if [[ "$1" == *".env"* ]]; then
echo "Error: Cannot edit .env files"
exit 1
fiCommon Hook Patterns
Formatting on commit:
npm run format
git add -u # Re-stage formatted filesPrevent commits to main:
branch=$(git rev-parse --abbrev-ref HEAD)
if [ "$branch" = "main" ]; then
echo "Cannot commit directly to main"
exit 1
fiRun tests on push:
npm test
if [ $? -ne 0 ]; then
echo "Tests failed. Push aborted."
exit 1
fiThis Week’s Sprint Work
Sprint 3 completion:
- PRD document: AI-assisted, covering your core feature
- Core feature functional: With data persistence
- 3 user tests: Watch people use it
- User feedback synthesis: What worked? What didn’t?
- Platform strategy decision: Web-only, PWA, or Capacitor?
Making Your Platform Decision:
Based on what you learned from user tests, decide your platform approach:
| If users said… | Consider… |
|---|---|
| “I’d use this on my phone” | Mobile-responsive, then PWA |
| “I’d use this at my desk” | Web-only is fine |
| “I want it as an app” | PWA first, Capacitor if needed |
| “I need it offline” | PWA with offline support |
Document your decision in your portfolio with reasoning. There’s no wrong answer, only informed choices.
Key Concepts
- Platform Spectrum: Web → PWA → Capacitor → React Native → Native
- Distribution Tradeoffs: Web (URL, SEO) vs. App Store (discovery, install)
- PWA (Progressive Web App): Installable web apps with offline support
- Capacitor: Wraps web apps for native app store distribution
- Service Worker: Enables offline functionality and caching
- Web App Manifest: Metadata for PWA installation
- Responsive Design: Adapting layouts to different screen sizes
- Mobile-First: Designing for mobile screens first, then scaling up
- Git Hooks: Automated scripts that run at commit/push time
- Husky: Tool for managing Git hooks in JavaScript projects
- Lint-Staged: Running checks only on staged files for speed