← All posts

·6 min read

Why a CI pipeline build beats a build from your laptop

A build that only works on one machine is a liability. Moving release builds into a pipeline makes them repeatable, auditable, and safe to hand to anyone on the team.

CI/CDDevOpsMobile
Contents
  1. The problem with local builds
  2. What a pipeline gives you
  3. A shape that works
  4. Make the pipeline the only way to release
  5. Keep it fast enough to love
  6. The same idea, on this site

Every team starts by building on a laptop. It is fast, it is familiar, and it works. The trouble shows up the day the one person with the right certificates, Node version and Xcode install is on holiday and a client needs a hotfix. A pipeline build removes that person from the critical path.

The problem with local builds

  • They depend on invisible state: global packages, cached pods, a stale derived-data folder, an environment variable set last March.
  • They are not reproducible. Two developers building the same commit can ship different binaries.
  • Signing keys and store credentials end up on personal machines, which is a security and bus-factor problem at the same time.
  • Nobody can tell afterwards exactly which commit a given build came from.

What a pipeline gives you

A pipeline starts from a clean runner every time, installs dependencies from a lockfile, and runs the same steps in the same order. If the build is green there, it is green for everyone. If it is red, the log is shared and the failure is not just on one laptop.

  • Clean environment: the build proves the repository is self-sufficient, not that your machine is.
  • One place for secrets: signing certificates and API keys live in the CI secret store, with access controlled and rotation done once.
  • Traceability: each artifact is tied to a commit SHA, a run, and a person who approved it.
  • Parallelism: tenants, platforms or flavours build side by side instead of one after another on your machine.
  • Your laptop stays free for actual work while the build runs.

A shape that works

Keep the pipeline boring and staged. Cheap checks run first so a typo fails in seconds rather than after a twenty-minute native build.

# .github/workflows/release.yml (simplified)
jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version-file: .nvmrc, cache: npm }
      - run: npm ci
      - run: npm run lint
      - run: npm test

  build-ios:
    needs: verify
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: bundle exec fastlane ios release   # signing and upload live here
        env:
          APP_STORE_API_KEY: ${{ secrets.APP_STORE_API_KEY }}

Make the pipeline the only way to release

The benefit disappears if people can still ship from their laptops whenever the pipeline is inconvenient. Restrict store credentials to CI, and let local builds exist for development only. Once that rule holds, a release is a button anyone on the team can press.

Keep it fast enough to love

  • Cache dependencies keyed on the lockfile hash, and native build caches where the platform allows.
  • Fail fast: lint, type-check and unit tests before any native compile.
  • Run only what changed when a monorepo allows it, but never skip the full build on release branches.
  • Publish artifacts (IPA, AAB, bundle) from every run so QA can install a build without asking an engineer.

The same idea, on this site

This portfolio follows it. Pushing to the main branch triggers a workflow that installs the exact dependencies, renders the resume PDFs with headless Chrome and the right fonts, builds the static site, and publishes it. The font is installed on the runner precisely because a local build and a CI build once disagreed about layout; the pipeline made that difference visible and fixable.

If it only builds on your machine, you have not finished building it.