TL;DR
- Figma reviews miss everything that's a function of the real device — touch targets, scroll momentum, keyboard behavior, font substitution, dark-mode transitions.
- Wrap
eas build --profile designer-previewin a Slack slash command so designers trigger their own preview builds without engineering. - Use an EAS Update
designer-previewchannel to push JS-only changes to an already-installed build — no reinstall, no rebuild. - Remove three friction points first: the install step, the "which build is this?" question, and the "is this update live yet?" question.
- Measure review-loop time, not build time.
Our mobile design reviews used to happen in Figma. Then a build would ship, the designer would see it on their phone a day later, and we'd realize the touch target was 8dp too small or the sheet animation felt wrong on Android. The fix was obvious in hindsight: put designers directly into the EAS preview loop so they see the change on a real device before signing off.
Here's how we wired it up and what actually moved the needle.
Why design reviews on Figma miss real device behavior
Figma reviews catch layout, spacing, and color drift. They miss everything that's a function of the device:
- Touch target size and reachability on the specific phone the designer holds every day
- Momentum and rubber-banding on real ScrollViews
- Keyboard behavior (especially on iOS Safe Area vs Android IME resize)
- Actual font rendering — system font substitution differs by OS version
- Dark-mode transitions in a real app vs mocked screens
Every one of these has bitten us. And every one of them is invisible until a designer scrolls, taps, and feels the app on their own device.
The one-Slack-command pattern that unblocks designers
The unlock was making it possible for a designer to trigger their own preview build without asking engineering. We wrapped eas build --profile designer-preview --platform ios in a Slack slash command:
/preview branch feat/new-onboarding
The command dispatches a GitHub Action that runs eas build against the named branch, then posts the QR code + install link back into the Slack thread when it completes.
# .github/workflows/designer-preview.yml (excerpt)
name: designer-preview
on:
workflow_dispatch:
inputs:
branch: { required: true }
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { ref: ${{ inputs.branch }} }
- uses: expo/expo-github-action@v8
with: { expo-version: latest, token: ${{ secrets.EXPO_TOKEN }} }
- run: eas build --profile designer-preview --platform ios --non-interactive --no-wait
The critical detail: --profile designer-preview in eas.json should be internal distribution, not TestFlight — TestFlight has an approval delay that breaks the loop.
EAS Update channels for designer-only preview builds
Once you have preview builds working, the second unlock is EAS Update for JS-only changes. Configure a designer-preview channel in eas.json:
{
"build": {
"designer-preview": {
"channel": "designer-preview",
"distribution": "internal",
"env": { "EXPO_PUBLIC_ENV": "designer" }
}
}
}
Any JS/TSX change (which is 80% of what designers care about — spacing, colors, typography, animation curves) can now be pushed to their existing installed build with eas update --channel designer-preview --branch feat/spacing-fix. No new install, no new build. The designer opens the app, pulls to refresh, sees the change.
This compressed our design-iteration loop from ~1 build/day to ~4-6 JS pushes/hour when we're in an active review.
The three friction points to remove before you invite designers
Before rolling this out, remove these:
The install step. Designers should not have to install Expo Dev Client from scratch every time. Ship one Dev Client build a week, keep it stable, and use EAS Update on top of it.
The "which build is this?" question. Add a corner label to your app in the designer env showing the branch name + short commit hash. A
useConstants()hook + a semi-transparentTextcomponent is enough:
import { Constants } from 'expo-constants';
const { manifest } = Constants;
// In your root layout:
<Text style={styles.watermark}>
{manifest?.extra?.branch} · {manifest?.extra?.commit}
</Text>
- The "is this update live yet?" question. Show the last-updated timestamp somewhere the designer can find (a debug menu, a settings screen). Nothing kills trust in the loop like reviewing an old version.
Conclusion: measure the review-loop time, not build time
After wiring this up, our design-to-shipped-mobile-build time dropped roughly 40%. But the metric that actually mattered wasn't build time — it was review-loop time: how long between "designer flags a change" and "engineer knows if the fix is right."
Measure that instead of build time and you'll instrument the right optimizations. Faster builds are useful; a designer who can review on-device without waiting for engineering is transformative.
Are you running designers through your EAS loop, or still bouncing builds over Slack manually? Drop a comment with how your review loop works — especially if you've found a cleaner way to handle the "which build is this?" problem.
Top comments (0)