Eight apps and one release spine
A portfolio of small apps is only cheaper than one big app if shipping each costs almost nothing. Play charges that cost per app, per year; a shared release system pays it once.
Eight Android apps ship from the SocialSure developer account, and I own the release engineering for all of them: signing, policy compliance, staged rollouts, and the annual scramble that Google Play schedules for every app on the store. The decision to run a portfolio of small apps instead of one large one is often argued as a bet on odds, many small chances at one hit. That framing misses where the money goes. A portfolio is only cheaper than a single product if the fixed cost of shipping each app is driven close to zero, and Play is structured so that the fixed cost never goes to zero on its own.
Play charges per app, per year
Two deadlines this year make the point. The target API level requirement says that from 31 August 2026 new apps and updates must target Android 16, API level 36, and existing apps must target at least API 35 to remain available to new users on newer devices, with an extension available to 1 November for apps that need it. That requirement has moved up one level nearly every year since 2018, and it applies to each app separately: eight apps, eight upgrades, eight rounds of finding out what the new target level breaks.
The second deadline is newer. Google's developer verification programme begins enforcement on 30 September 2026 in Brazil, Indonesia, Singapore and Thailand, where apps must come from verified developers to install on certified devices, with the June 2026 announcement describing the expansion to all certified devices in 2027. Verification is per developer rather than per app, but every app carries the account's status, and an account with eight apps has eight places for a verification problem to become a user-facing one.
Add the ordinary annual items: the policy declarations that change wording each year, the data safety form, the permissions review, the signing key hygiene, and the update that every app needs simply because its libraries moved. None of these is large. All of them are per app. Eight apps with separate pipelines pay them eight times, and the total is a quiet tax that grows with every app you add.
The target API deadline is the clearest example of how the tax compounds, because it is not one task. Raising the target level changes runtime behaviour: permissions that were granted at install become requests at use, background work that used to run is now scheduled or refused, storage paths that were open are now scoped. Each app has to be rebuilt against the new level, run through its screens, and shipped through a rollout before the date. For an app that has not been touched in a year, that rebuild also drags every library forward, and the libraries have their own opinions. Done separately, it is a week per app. Done through a shared pipeline with the same dependency baseline, it is a week for the baseline and a day per app to confirm.
The spine
The only way a portfolio stays cheap is if the per-app cost is paid once, by a shared system, and each app plugs into it. I think of that system as the release spine, and it has four vertebrae.
The keys. Every app is enrolled in Play App Signing, so the key devices trust is held by Google and the key I handle is an upload key, stored in the CI secret store and nowhere else. New apps get a fresh upload key from the same procedure, and no key lives on a laptop.
The pipeline. One CI configuration builds, tests, signs and uploads a bundle, parameterised by the app. The Habits app builds on GitHub Actions in a public repository, and the shape of that workflow is the shape of all of them: a build step, a verification step, a signing step that never sees the key in plaintext, and an upload to a named track. A new app is a new set of parameters, not a new pipeline.
The policy checklist. A single document lists every declaration Play requires and the answer for each app, kept as data so that a policy change is one row edited eight times, not eight forms filled from memory.
The rollout ladder. Every release walks the same staged rollout, with the same halt conditions at each stage, so that a bad release in any app is caught by the same reflex.
What the spine does not share
The spine holds the questions; each app holds its own answers. That distinction is what keeps a shared release system from becoming a shared liability. The data safety form asks the same questions of every app, so the checklist is shared, but an offline habit tracker and a multiplayer card game answer them differently, and the answers live with the app. The rollout ladder is shared, but the halt condition for a game with a live server is tighter than for a tool that never touches the network. The pipeline is shared, but each app's tests are its own, and a green build on the spine means only that the app compiled, signed and uploaded, not that it works.
Keeping that line clear also keeps the failure modes separate. A mistake in the spine, a wrong signing step or a policy answer copied to the wrong app, is caught by the first app through it and fixed once. A mistake in an app's answers is that app's problem and nobody else's. The account carries the consequences either way, which is the strongest argument for making the shared part small, well tested, and boring.
The ninth-app test
The test I run before agreeing to add another app is to estimate, honestly, how much un-automated effort it would take to ship a hypothetical ninth app to production: create the listing, enrol the key, wire the pipeline, complete the declarations, walk the first rollout. If the answer is more than one working day, the spine is not finished, and the portfolio is already too expensive to grow. The ninth app is not a plan. It is a measurement of the spine, and a spine that fails the test needs work before the next real app, not after it.
The test has a second use. It tells you what to automate next. Whatever step of the imaginary ninth app takes longest by hand is the vertebra that is missing, and it is usually not the one you expected. For a long time mine was the policy declarations, which I had been answering from memory for each app, and the fix was a spreadsheet, not code.
What the model says and does not say
The chart is a model, and its two assumptions are the whole argument: separate pipelines cost a roughly fixed number of days per app per year, and a shared spine costs a larger fixed amount once plus a small amount per app. Change the numbers and the crossing point moves, but it does not disappear, because a per-app line always crosses a mostly-flat one eventually. What the model does not say is that the spine is free to build. Twenty days is a real month of work that a one-app company should not spend, and the right time to build the spine is when the second app is real, not when the first one is.
It also does not say that the spine makes the apps good. It makes them shippable, which is a different property. Eight apps that ship on time with no policy strikes and no key incidents can still be eight apps nobody wants, and the spine will not tell you that. It only guarantees that finding out costs a day rather than a fortnight.
The rule
Count the un-automated days for the ninth app. If it is more than one, stop adding apps and add a vertebra. If it is one or less, the portfolio is a portfolio, and the next question is which app deserves the day.
Get new posts by email
Occasional essays on engineering, AI, and building for the people technology leaves behind.
Subscribe with RSS