Your App Should Still Be Yours When the Developer Leaves
Most handovers get the code across. The things that decide whether someone else can ship next week are the history, the keys, and whose name is on the accounts.

If the person who builds your app stopped answering tomorrow, could someone else ship a fix next week?
It is easy to assume yes, because the code is "in the repo". That is usually true and rarely enough. Code is the part of a mobile app that survives a handover best. What decides whether the next developer ships in a week or spends a month reconstructing is everything around it: the history that explains the code, the keys that sign it, and the accounts it ships through.
Nobody plans for this. A developer relationship ends the way most working relationships do: gradually, politely, often with a promise to "send everything over". The gaps only show when the new person asks for something and the answer is a pause.
I have taken over apps from a solo developer and from an agency, and neither handover was hostile. Both still had a gap that would have cost real time if nobody had gone looking.
Taking over an app from a previous developer: the code arrived, the history didn't
I came back to lead a message-scheduling app whose Android code I had first written years earlier. Other developers had maintained it since. When I asked for the current code, it turned out nobody had noticed it wasn't in the repository.
The last commit on the shared remote was eight months old. The app's version number had moved on by twenty builds since then. That work had existed only outside the shared remote. The developer pushed it once asked, and it arrived like this:
$ git log --format='%ad %s' -2 # dates replaced with what they mean; version number removed
my first day FIX Schedule All feature Fix Dual WhatsApp on new OS | Show Pro again
Change placeholder icon fix delays in sending <version>: Added wait
time and fix whatsApp sending
8 months earlier FIX Schedule All feature
$ git show --shortstat <that commit>
93 files changed, 3184 insertions(+), 809 deletions(-)
Eight months of work, twenty builds, one commit. The code came back; the reasons behind it did not.
The code itself came back. What is gone is the sequence: which change fixed which bug, what the sending delay was added to work around, which of those 93 files moved together and why. Run git blame on any line inside that commit and it gives the same answer: that one commit, dated the day I started.
That cost doesn't come as one bill. It comes as friction whenever someone touches one of those files and has to rediscover a decision instead of reading it. The ironic detail is that the history of the code I wrote years ago survived intact. The most recent work, which is what matters most right now, is the part nobody can explain.
The fix is not heroic. It is a rule written into the engagement from day one: work lives on a remote the business owns, pushed at least daily, on branches with real commit messages. If a developer's machine can contain something the business does not have, the business does not own its app. It owns a snapshot.
Moving app development in-house from an agency: the first week is about secrets
The second handover was planned and friendly. A healthcare workforce marketplace had been built by an agency. The client's stated reason for moving in-house was flexibility: every change had become a scope change with its own approval, and a product still finding its shape changes constantly.
The agency developer and I overlapped for about a week, and that week is visible in the repository:
| Quarter | Outgoing agency developer | In-house (me) | Pipeline bot |
|---|---|---|---|
| 1st full quarter | 474 | — | — |
| 2nd | 440 | — | — |
| 3rd | 298 | — | — |
| 4th (handover) | 52 | 149 | 37 |
| 5th | — | 205 | 66 |
| 6th | — | 140 | 60 |
A clean handover leaves a seam in the history, not a gap: one quarter of overlap, then the work continues at pace. (Commits per quarter; other contributors omitted.)
A large part of my first week went on credentials, not features, and some of them lived inside the repository itself:
ios/fastlane/AuthKey.json | 6 -
.env.production.json
- "SENTRY_DSN": "https://<redacted>@<org>.ingest.de.sentry.io/<project>",
+ "SENTRY_DSN": "${SENTRY_DSN}",
+ "FIREBASE_ANDROID_API_KEY": "${FIREBASE_ANDROID_API_KEY_PROD}",
+ "FIREBASE_IOS_API_KEY": "${FIREBASE_IOS_API_KEY_PROD}",
The key that lets a pipeline upload builds to App Store Connect was committed to the repository, so anyone who could read the code held it.
AuthKey.json was an App Store Connect API credential file: the key a pipeline uses to upload builds. It's convenient in a repo, because the pipeline finds it without setup. It's also a publishing credential sitting next to the source, readable by every past and future contributor. The committed values were replaced with references the CI system fills in from its secret store, and the pipeline got its own bot identity so automated commits are attributable to the pipeline, not to a person.
Moving a secret out of the repo is only half of it. Git keeps every version of every file, so a key that was ever committed is still in the history. The complete fix is to rotate it: revoke the old one in the console and issue a new one that only ever lived in the secret store. That takes an admin on the account, which is the next problem.
The payoff of doing this in week one, not month three: the first release after the handover was cut about two weeks after I started.
Who should own the Google Play and App Store accounts
The pattern that makes both stories above boring, and boring is the goal, is that the business owns the organisation and the developer is a guest in it.
My own Play Console login opens onto several developer accounts belonging to businesses I have built for. In each of them I am an invited user with the roles I was given. None of them is mine. If a client removes me tomorrow, it is one click in their console, and nothing about their app, their listing, their signing or their revenue changes. App Store Connect works the same way: the business enrols in the Apple Developer Program as an organisation and adds the developer under Users and Access.
The opposite arrangement, the developer enrolling "to save time" and transferring later, creates a risk nobody needed to take. App transfers between accounts are possible on both stores, but they are a process, not a click, and they need the co-operation of whoever currently holds the account.
The same discipline applies to the business's own records of who owes what. On my own apps I keep one table per app where every provisioning item (store account, signing key, ad unit, analytics project) carries a single tag: owner or developer. I added that after a status report on one of my apps said two items were waiting on the owner for nine days, when the project's own playbook already assigned them to the developer. The report had drifted from the source of truth, and nine days is what that drift cost. Ownership that lives in people's heads drifts. Ownership that lives in a table can be checked.
The app handover checklist
This is the list I work through when I take over an app, and the list I'd hand a founder before they hire anyone. The rule for every row is the same: the business owns it, the developer is granted access to it.
| Asset | The business owns | The developer gets |
|---|---|---|
| Google Play developer account | The organisation account | Invited user, scoped roles |
| Apple Developer Program / App Store Connect | Organisation enrolment | User in Users and Access |
| Source code repository | The org/workspace on GitHub, GitLab or Bitbucket | Member access, pushes at least daily |
| Git history | Every branch, with real commit messages | — |
| CI/CD | The CI account and its secret store | Permission to edit pipelines |
| Android signing | Play App Signing enabled; upload key stored by the business | Upload key via the secret store |
| iOS signing and upload | Distribution certificates, App Store Connect API keys | Keys via the secret store, never in the repo |
| Backend, Firebase, cloud projects | The project and its billing | IAM role |
| Crash reporting and analytics | The Sentry/Crashlytics/analytics org | Member |
| Domain and DNS | The registrar account | Nothing, or a DNS role if needed |
| Third-party API keys and billing (ads, subscriptions, maps, email) | Accounts on a business card | Keys via the secret store |
| Support email and store contact details | A business mailbox | Access if they handle support |
If a row's left column has a person's name in it instead of the business's, that row is the next handover's problem.
Two rows are worth a sentence each, because they fail silently. Play App Signing means Google holds your app's signing key and you hold an upload key, so a lost upload key is a reset request from the account owner, not the end of your app. Git history is the only row a founder can't audit by logging into a console, so ask to see the commit log, not just the repository.
You don't need a crisis to use this. Twenty minutes with the table and your own logins will show which rows already say "the business". Any row that doesn't is cheaper to fix while everyone is still answering their messages.
If you're mid-handover, or already on the far side of one with a repository that doesn't explain itself, that's the kind of work I take on. The first week usually looks like the one above: find what the business doesn't hold yet, and move it.
Ramiz Raja is a senior mobile developer and technical lead with 12+ years shipping and rescuing production apps on Android, iOS, and Flutter. More at codebyramiz.com.