Building Multiple iOS Apps: What 72 Releases Taught Us

How a small studio shipped 72 iOS apps: one core loop per app, shared templates per app family, AI behind a backend, App Store names and batch updates.

· 6 min

We are BernSoftware, a small software studio in Istanbul, founded in 2020. Between 2024 and 2026 we put 72 apps on the App Store: AI scanners that identify wine labels, coins or trading cards, health trackers, utilities like an NFC reader/writer, and a few puzzle and party games.

That is a lot of apps for a team our size. We only managed it because we stopped treating each one as a fresh project. Here is what that took.

1. Scope the MVP around a single loop

Almost every app we ship is built around one core loop. An identifier: point the camera, get an answer, save it to a collection. A tracker: log something, see a trend, get a reminder. A game: one input, one rule, steadily harder levels.

A feature that does not serve the loop goes on a "later" list. The first version only has to prove that the loop is worth repeating; settings, sharing and themes can wait. A useful test: if you cannot describe the app in the 30 characters Apple gives you for the name, the scope is too wide.

2. Build families, not one-offs

The catalogue falls into a few families:

  • Camera identifiers. At least 17 of the 72 take a photo and return a structured result: art, fish, wine, toys, mould, mushrooms, plants, stones, coins, jewellery, antiques, archaeological finds, comics, sports cards, TCG cards, perfume and food allergens.
  • Generative image tools. Hair and beard try-on, virtual fitting room, car modification, interior design, logos, T-shirt designs and photo restoration.
  • Text assistants. Email writing, paraphrasing, note summarising, flash cards from PDFs and homework help.
  • Trackers and utilities. GLP-1 dose logging, calorie tracking, pet care reminders, alarms, widgets and NFC tools.

Inside a family, most of the work is shared: camera capture, upload, the result screen, the collection list, onboarding and settings. What changes per app is mostly configuration. A simplified sketch for an identifier:

// Simplified sketch: one identifier template, many apps
type ScannerConfig = {
  appId: string;
  subject: string;            // "wine label", "coin", "mushroom"
  resultFields: string[];     // what the result card shows
  prompt: (locale: string) => string;
  theme: { accent: string; icon: string };
};

export const wine: ScannerConfig = {
  appId: "wine-scanner",
  subject: "wine label",
  resultFields: ["winery", "vintage", "grape", "region"],
  prompt: (l) => `Identify the wine in this photo. Answer in ${l} as JSON with: winery, vintage, grape, region.`,
  theme: { accent: "#7c1f3d", icon: "wine" },
};

A new identifier then mostly means a new config, icon, screenshots and prompt, plus testing against real photos. One caveat: extract a template from apps that already work, not from a guess about what will repeat.

3. Pick the stack per app, not per studio

Our default is React Native with TypeScript and Expo, because for most consumer apps one codebase and fast iteration matter more than deep platform access. When the core loop depends on hardware, we go native in Swift from day one. Our hidden-camera detector, for example, combines CoreBluetooth scanning for BLE devices with a CoreML object-detection model that runs on the device. A bridge you have to maintain costs more than starting native.

4. AI features are a pipeline problem, not a model problem

Most of our AI apps call hosted models: LLM APIs for the text assistants, and models such as Stable Diffusion, GFPGAN and Real-ESRGAN on cloud GPUs for the image apps. Choosing a model was the easy part. The hard part was everything around it:

  • Keep keys and prompts on the server. The app calls our backend, which calls the provider. We can then change providers, fix prompts and rate-limit without an app update.
  • Queue heavy jobs. For apps like the hair try-on, a Node.js job queue sits in front of the GPU workers and pushes progress to the app over WebSockets, so users see real progress instead of a frozen spinner.
  • Shrink images on the device first. Compressing and cropping before upload cuts bandwidth and latency.
  • Ask for structured output. Identifiers request JSON with fixed fields and validate it before rendering. A result card should never show raw model text.
  • Keep personal data on the device. Our GLP-1 tracker uses an encrypted local SQLite database, and our photo vault keeps its data local. Not every feature needs a server.

5. Treat App Store metadata as part of the product

The App Store gives you 30 characters for the app name. All 72 of our names fit, and 64 use 25 or more characters. Most follow one pattern: a short brand, a separator, then the search phrase, as in "CardSnap | Sports Card Scanner" or "GLP-1 Tracker: Dose Log". The brand gives identity; the phrase uses the words people actually search for.

Write metadata and screenshots alongside the first build, not the night before submission. If three screenshots cannot show the core loop, the scope is too wide.

For review, prepare for metadata and permission issues as much as for bugs. Permission prompts need a specific purpose string, and the app must still work after "Don't Allow".

6. Localise names and copy, not just strings

We are a Turkish studio selling worldwide, and it shows. Some apps have Turkish store names ("Pasaport Fotoğrafı | Vize ID"); others pair an English brand with Turkish search terms ("Coin ID: Para Değer Tarayıcı"). Our outfit scanner names Trendyol next to Zara, H&M and Amazon, because those are the stores its users shop at.

  • Translating UI strings is the easy part. Store name, subtitle and keywords need their own research per market.
  • For some apps, such as an English vocabulary trainer or a multi-language Bible reader with text-to-speech, localisation is the product, not a finishing step.
  • Pass the user's locale into AI prompts, so a Turkish speaker gets a Turkish result card without a translation step.

7. Maintaining 70 apps means doing everything in batches

Every iOS release brings new SDK requirements, screen sizes and permission rules. Patching 72 apps one by one is not realistic, so we work family by family: apps that share code can take a fix or an SDK bump that is tested once.

What helps:

  • Keep each app's config, metadata and screenshots in the repository, next to its code.
  • Decide on purpose which apps to keep. Removing an app from sale beats letting it rot.
  • Watch the backend as closely as the apps. A provider outage looks like a broken app to the user.

Closing thought

None of this needs a big team. It needs one loop per app, shared code extracted only after you have written it twice, and store metadata treated as seriously as the code.

Planning a project like this?

Plan it in 10 steps