Sweat beading on my forehead, that 13-inch M5 MacBook Air humming like a spaceship pre-launch—another Expo build explodes in flames.
That’s the scene. Me, a VibeCoder, not typing code but dreaming it into existence via Claude AI, chasing the holy grail: a CI/CD pipeline that shoves my React Native CRM app straight onto therapists’ iPhones. Arc, my mobile beast for bodywork pros—28 files, 27 screens, 85% MVP done with Supabase humming in the backend. Code? Claude spits it out in minutes. But that last mile to testers? Pure hell.
Why VibeCoders Bleed on Deployment, Not Syntax
Look. AI’s the ultimate platform shift—like electricity flipping factories from steam. Suddenly, anyone’s a builder. I describe vibes; Claude codes screens. Energy surges. But push to main? Crickets. Or crashes.
TestFlight queues drag like molasses. Expo Go chokes on native modules. EAS cloud? Paywall for solos like me feels like robbery.
Enter the hero stack: Expo + GitHub Actions on a self-hosted runner (my Mac) + DeployGate. Push. Wait 10 minutes. Testers grab .ipa at a magic URL. Zero dollars. Unlimited.
But glory? Buried under 11 failures. Each a gut punch teaching VibeCoders why CI/CD’s the new superpower.
For a VibeCoder, this “last mile” is the biggest bottleneck — not writing code, but delivering what you’ve written.
Damn right. That’s the fire.
Push one: Boom. “Embed Pods Frameworks” crash at 3:54 AM.
Two workflows duked it out on main—one for DeployGate, one TestFlight. Mac’s Xcode choked, resources tapped out.
Fix? Banish TestFlight yaml to workflows-disabled purgatory. Simple mkdir, mv. Clean.
But wait—next push uploads 15MB binary blobs. .ipa and certs snuck into git. Rookie sin.
.gitignore to the rescue: build-*.ipa, AppleWWDRCAG3.cer. Purge history. Lesson screams: artifacts ain’t repo pets.
Is Self-Hosted GitHub Runner a MacBook Savior or Trap?
Failure four: Pods crash redux. Sneaky react-native bump from 0.83.2 to .4, plus react-native-worklets peer dep ambush from reanimated.
How’d I sleuth? Checkout last good commit’s package.json, npm ci, local eas build. Success!
Pin deps. Add the ghost dep. Stability reigns.
Five: Local builds fly, CI flops. Stale node_modules, Xcode DerivedData ghosts haunting /tmp.
Now here’s my unique twist—no article spells this—but these fails echo the Wright Brothers’ Kitty Hawk grind. Over 1,000 glider crashes before powered flight. VibeCoding’s the glider age: AI prototypes soar in sims, but real skies (deploys) demand brutal iteration. Prediction? In five years, AI will auto-pipe CI/CD too, but today’s pioneers like us forge the wings.
Workflow hack: Cache nuke step.
- name: Clean caches
run: |
rm -rf ~/Library/Developer/Xcode/DerivedData/Arc-*
rm -rf /tmp/eas-build-local-nodejs
rm -rf /tmp/eas-cli-nodejs
Six: EAS snubs local creds, phones home. EAS_CREDENTIALS_SOURCE=local ignored by eas-cli 18.5.0.
Patch: eas.json decree.
"preview": {
"distribution": "internal",
"credentialsSource": "local"
}
Seven: credentials.json ghosts—gitignored, naturally. Checkout skips it.
Workflow copies from ~/client-crm/. Boom, present.
Eight—final boss tease: Code signs perfect, then “Embed Pods” at unlock. LaunchAgent runner can’t touch GUI keychain.
Unlock ritual:
- name: Unlock keychain
run: security unlock-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" ~/Library/Keychains/login.keychain-db
GitHub Secrets holds the password. Sacred.
Attempt 12: Green across the board.
✔ Using local iOS credentials (credentials.json) ✔ Archive Succeeded ✔ Successfully exported and signed the ipa file ✔ Uploading to DeployGate… ✔ Distribution page updated
Git push to tester swipe: 10 minutes flat.
The Bulletproof Workflow That Ate 11 Corpses
Here’s the survivor, battle-scarred:
name: Build & Deploy to DeployGate
on:
push:
branches: [main]
workflow_dispatch:
jobs:
build-and-deploy:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- name: Clean caches
run: |
rm -rf ~/Library/Developer/Xcode/DerivedData/Arc-*
rm -rf /tmp/eas-build-local-nodejs
rm -rf /tmp/eas-cli-nodejs
- name: Install dependencies
run: npm ci
- name: Copy credentials
run: |
cp ~/client-crm/credentials.json ./credentials.json
cp -r ~/client-crm/credentials ./credentials
- name: Unlock keychain
run: security unlock-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" ~/Library/Keychains/login.keychain-db
- name: Build .ipa
run: eas build --platform ios --profile preview --local
# ... (DeployGate upload steps implied)
Adapt it. Your Mac’s the runner—install via GitHub docs. DeployGate? Free tier dev distributions, fixed URLs for testers. No App Store dance.
Energy restored. Arc lives on phones. Therapists log clients mid-massage.
But here’s the wonder: AI didn’t just code Arc. It vibe-fueled the pipeline debug—Claude dissected errors faster than Stack Overflow spelunking.
Platform shift complete. VibeCoders deploy like gods.
Short para punch: Scale it.
Long explore: Self-hosted shines for solos—your hardware, your rules. Cloud? Latency, costs creep. But watch RAM; my Air held, barely. M-series magic. Future? ARM runners everywhere. Expo’s local builds—underrated gem. No cloud tax. Pair with Supabase edge functions? Dream.
One sentence: Bliss.
Why Does Expo + DeployGate Crush for Indie Devs?
Corporate hype calls EAS “easy.” Bull. Subscriptions sting solos. This? Free forever. Fixed tester URLs—magic for non-tech users. Therapists tap links, install. No emails, no hunts.
Downsides? Mac-only for iOS local. Android? EAS or fastlane next. Self-runner setup: 30 mins first time.
Thrill? Every push iterates the world.
🧬 Related Insights
- Read more: 10,000 Planes Dancing on a Framework-Free 3D Globe in Your Browser
- Read more: Claude Isn’t Your Architect. Full Stop.
Frequently Asked Questions
How do I set up a self-hosted GitHub Actions runner on Mac for Expo?
Install via GitHub docs: Add repo secret RUNNER_TOKEN, run config.sh on your Mac. Label it ‘self-hosted’. Done—your M1/M2/M3 beast builds.
What’s the best free way to distribute Expo iOS builds to testers?
DeployGate. Sign up, grab API key, add workflow upload step. Testers hit your-app.dgate.io—installs OTA-style. No reviews.
Why do Expo builds fail on ‘Embed Pods Frameworks’ in CI?
Stale caches, dep drifts, keychain locks. Nuke DerivedData, pin packages, unlock keychain. Always.