Back to blog
Engineering13 min read

Prompting for Mobile Development (Swift, Kotlin, React Native)

Honest mobile dev prompts for AI: what Swift 6.3, Kotlin 2.4, and React Native 0.87 code an LLM can actually be trusted to write, and the bounded tasks worth prompting for at all.

NH
Nafiul Hasan

TL;DR: AI does not know which Swift, Kotlin, or React Native version your project targets unless you say so, and all three move fast enough that a model's training data is already behind. Name the exact version and API level in every prompt, paste the real error verbatim, and scope requests to one screen or one crash at a time.

What Can AI Actually Do for Mobile Development?

Start with the honest limit, because it's where most wasted mobile prompts come from. A model has never launched your app on a real device. It has not felt whether a screen transition stutters on a three-year-old Android phone, whether a SwiftUI list scrolls smoothly with real data, or whether a bridge call adds a visible frame drop. It cannot profile your app, read your crash reporter, or know which OS version your actual users are still running. Any claim that an AI tool can build your app end to end from a single prompt is describing a demo project, not a codebase serving real users.

What it does well is narrower: producing a first draft you'll edit, explaining an unfamiliar API, or writing boilerplate for a pattern you already understand well enough to check. Treat it like a fast junior engineer who has read an enormous amount of documentation but has never opened your Xcode project, your Android Studio project, or your package.json. If prompt structure itself is new to you, our beginner's guide to prompt engineering covers the fundamentals this post assumes.

Mobile prompting has a wrinkle that generic "AI coding" advice tends to skip: three genuinely different platforms, each with its own language, its own build tool, and its own release cadence, and each one changing meaningfully several times a year. A model trained on a mix of pre-Swift-6 concurrency patterns, Kotlin 1.9 syntax, and React Native's old bridge architecture will confidently blend all three eras together unless you tell it which one you're actually building against. That's not a model being careless; it's doing exactly what you'd expect when the prompt never said which real, differently-shaped API to assume.

Why Does Naming the Exact Toolchain Version Matter So Much Here?

None of these three platforms is slow-moving. Swift shipped 6.3 in March 2026 and has since patched forward to 6.3.3; Kotlin shipped 2.4.0 in June 2026 and a bug-fix 2.4.10 in July; React Native shipped 0.87 in August 2026 and raised its minimum required Node.js version in the same release. None of these are frameworks you can safely prompt against from memory, your own or the model's.

The failure mode repeats across all three platforms in the same shape: the model defaults to whatever pattern was most common in its training data, which skews toward older, better-documented versions, and it produces code that looks complete but calls a method, property, or flag that has since been renamed, removed, or made mandatory. React Native 0.87 is a clean, literal example of this risk. It removed the useTurboModules feature flag entirely, because TurboModules are now always enabled — a prompt asking a model to "make sure the new architecture is turned on" is asking about a toggle that no longer exists in this or any later release. This is the same discipline our post on prompting for game development argues for engine code; the difference here is that you're juggling three separate platforms competing for the same phone, not three engines competing for the same PC.

Prompting for Swift and SwiftUI: What Changed in 6.3

Current release, verified against Swift.org on September 4, 2026: Swift 6.3, which shipped March 24, 2026 and has since moved to the 6.3.3 point release. If your prompt just says "Swift," you're leaving the model to guess between that and whatever Swift 5.x codebase makes up most of its training data.

The detail that actually changes what "correct" code looks like is the project's language mode, not just the installed compiler version. Swift 6 language mode treats concurrency-safety violations — touching mutable state from the wrong actor, capturing a non-Sendable type across a task boundary — as compiler errors rather than warnings. A codebase still opted into Swift 5 language mode, which is common in projects migrated gradually rather than all at once, will happily compile code that Swift 6 mode would reject outright. Telling a model your target's language mode, not just the Swift version installed on your Mac, is what actually determines whether generated concurrency code will build.

import SwiftUI

@MainActor
final class ProfileViewModel: ObservableObject {
    @Published var name: String = "Loading..."
    @Published var errorMessage: String?

    func loadProfile(id: String) async {
        do {
            let url = URL(string: "https://api.example.com/users/\(id)")!
            let (data, _) = try await URLSession.shared.data(from: url)
            let profile = try JSONDecoder().decode(Profile.self, from: data)
            self.name = profile.name
        } catch {
            self.errorMessage = "Could not load profile: \(error.localizedDescription)"
        }
    }
}

struct Profile: Decodable {
    let name: String
}

Nothing in that sample depends on a feature unique to 6.3 specifically — @MainActor, ObservableObject, structured concurrency, and URLSession are all long-standing, stable parts of the API, which is exactly why it's a safe boilerplate request. Ask for a bounded piece like this, verify it compiles under your project's actual language mode, and you've used AI for what it's actually good at here.

Prompting for Kotlin and Jetpack: What Changed in 2.4

Current release, verified against Kotlin's own documentation on September 4, 2026: Kotlin 2.4.10, a bug-fix release of 2.4.0 that shipped July 14, 2026. The change worth naming in every prompt touching Kotlin internals: Kotlin's own release notes for 2.4.0 state plainly: "Starting with Kotlin 2.4.0, the compiler no longer supports -language-version=1.9. As a result, the K1 compiler is no longer supported." Every Kotlin project on 2.4.x compiles through K2, full stop — a model repeating K1-era compiler-plugin advice or K1-specific error messages is describing a toolchain your project cannot use anymore.

The same release promoted a real language feature to stable: Kotlin's docs note that "Kotlin 2.4.0 promotes context parameters, explicit backing fields, and annotation use-site targets features to Stable." If you're prompting for code that uses context parameters, naming 2.4.0-or-later isn't optional busywork; earlier Kotlin versions treat the feature as experimental at best, or don't support the finished syntax at all.

class UserRepository(private val api: UserApi) {
    suspend fun loadUser(id: String): Result<User> = withContext(Dispatchers.IO) {
        try {
            Result.success(api.fetchUser(id))
        } catch (e: IOException) {
            Result.failure(e)
        }
    }
}

@Composable
fun UserNameLabel(name: String, modifier: Modifier = Modifier) {
    Text(text = name, modifier = modifier)
}

The Kotlin version you name is only half the picture on Android, and this is the detail most prompts miss entirely. React Native 0.87 requires Kotlin 2.0 or newer for its Android build, but it actually bundles Kotlin 2.2.0 internally — two full feature releases behind the 2.4.10 you'd get installing Kotlin standalone today. If you're prompting for code inside a React Native app's android/ folder, the model needs to know it's targeting the version React Native actually bundles, not the version your terminal reports when you run the Kotlin compiler directly on its own. Android's own platform moved forward too: Android 17, API level 37, is the current target per Google's developer documentation, and it introduces a new ACCESS_LOCAL_NETWORK runtime permission and tighter rules around background audio that a model trained on older targetSdkVersion conventions won't know to ask for.

Prompting for React Native: What Changed in 0.87

Current release, verified against React Native's own blog on September 4, 2026: React Native 0.87, announced August 11, 2026. Two changes in this specific release matter more than most for prompting.

The first: the New Architecture stopped being optional. React Native's own changelog for 0.87 confirms: "Removed the useTurboModules feature flag (TurboModules are always enabled)." A prompt for a native module that doesn't say "New Architecture" isn't describing an opt-in choice anymore; it's describing the only architecture that exists in this and every future release. A model trained on a lot of 2022–2023-era tutorials will default to the legacy NativeModules bridge pattern precisely because that's what most of the internet's existing content still shows, and that pattern is not one your current project can rely on.

The second: iOS dependency management started to change, cautiously. React Native's own release notes state: "React Native 0.87 adds experimental support for Swift Package Manager as an alternative to CocoaPods on iOS. It is opt-in and additive; CocoaPods remains the default and the supported path." So the default assumption for a prompt should still be CocoaPods, unless you've deliberately opted your project into the new SwiftPM path — telling a model your iOS dependencies are Swift Package Manager when they're actually CocoaPods, which is still true for the overwhelming majority of projects, produces import statements and Podfile edits that don't match your project at all.

import { useEffect, useState } from 'react';
import { ActivityIndicator, Text, View } from 'react-native';

function UserBadge({ userId }: { userId: string }) {
  const [name, setName] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;
    fetch(`https://api.example.com/users/${userId}`)
      .then((res) => res.json())
      .then((data) => {
        if (!cancelled) setName(data.name);
      });
    return () => {
      cancelled = true;
    };
  }, [userId]);

  if (!name) return <ActivityIndicator />;
  return (
    <View>
      <Text>{name}</Text>
    </View>
  );
}

export default UserBadge;

The release also raised the toolchain floor in ways that are easy to miss if you're prompting from an older mental model: Node.js 22.13.0 or newer is now required, Android's minCompileSdk moved to 34, compileSdk/buildTools moved to 37, and 0.87 is the first React Native release to support Android Gradle Plugin 9. If you're asking a model to help debug a Gradle build failure, naming which AGP version your project is actually on, 8.x versus the newly-supported 9, changes which flags and DSL syntax are even valid to suggest.

Which Version Mistake Shows Up Most Often, Per Platform?

Versions verified against swift.org, kotlinlang.org, and reactnative.dev, September 4, 2026.
FeatureSwift 6.3 (iOS)Kotlin 2.4 (Android)React Native 0.87
Toolchain fact worth naming every timeLanguage mode (Swift 6 vs. Swift 5) — determines whether strict concurrency checks are errors or warningsK2-only compiler since 2.4.0 — K1-era plugin and error-message advice no longer appliesNew Architecture (TurboModules/Fabric) is mandatory as of 0.87; the legacy bridge doesn't exist anymore
Most common version mistakeConcurrency code correct under looser Swift 5 mode rules, wrong under a Swift 6 mode targetAdvice written for the retired K1 compiler, or a mismatch with the Kotlin version a framework actually bundlesLegacy NativeModules/bridge code from older tutorials, or assuming CocoaPods is gone when SwiftPM is still opt-in
Bounded task AI handles well hereA single ObservableObject or async function, checked against your project's actual language modeA single suspend function or Composable, checked against the Kotlin version your build actually usesA single functional component or hook, checked against your project's confirmed architecture

How Do You Debug a Native Crash Log With AI?

The single most useful debugging prompt across all three platforms is boring on purpose: paste the actual crash log or stack trace verbatim, name the exact platform and version, and describe only the one system involved.

I'm on Swift 6.3, targeting iOS 18. This crash happens when tapping
the "Save" button on the profile screen. Here's the exact crash log:

Fatal error: Unexpectedly found nil while unwrapping an Optional value
  at ProfileEditViewModel.swift:42

Here's the only function involved: [paste just that function]

A vague description like "my app crashes sometimes" gives a model nothing to reason about beyond guessing at the most statistically common cause in its training data, which may have nothing to do with your actual bug. Real error text, not a summary of it, is the single change that fixes most unproductive mobile debugging sessions — and it costs you nothing but a copy-paste.

How Do You Keep Project Context Across Prompts Instead of Repeating It?

The exact-version discipline above only holds up if you keep repeating it every prompt, which nobody does past the first afternoon. The durable fix is writing it down once, in a file a coding assistant reads automatically rather than a block you retype each session. A short project-instructions file naming your Swift or Kotlin version and language mode, your minimum OS target, your UI layer, and your React Native architecture status removes an entire category of prompts you'd otherwise write from scratch every time. Our CLAUDE.md templates for Claude Code is a reasonable starting shape for that file, and our deeper guide to context engineering for coding agents covers how to structure it once your codebase is too large for any single prompt to hold. Once code compiles against the right toolchain, our AI prompts for code review, debugging, and refactoring cover the pass that comes after.

Free Chrome Extension

Stop rewriting prompts. Start shipping.

Works with ChatGPT, Claude, Gemini, Grok, Midjourney, Ideogram, Veo3 & Kling. 4.8★ on the Chrome Web Store.

Create An Account

A Reusable Mobile Prompt Template

Everything above collapses into one repeatable shape. Fill in the brackets and the rest of the discipline follows automatically:

Platform: [Swift 6.3 / Kotlin 2.4 / React Native 0.87 — your exact version]
Target: [iOS 18+ / Android API 26+ / RN New Architecture only — be specific]
Task: [one bounded thing — one screen, one function, one crash, not "the app"]
Context: [paste only the relevant file or class, not the whole project]
Constraints: [naming conventions, existing patterns to match, what NOT to touch]

None of it is clever. It's the same four habits repeated three times, once per platform: name the exact version, scope the request to something you can read in full, paste real context instead of a description of it, and verify the output against your project rather than against how plausible it looks. That's the whole difference between AI-generated mobile code that compiles on the first try and code that looks right until you actually build it.

Frequently asked questions

Free Chrome Extension

Stop rewriting prompts. Start shipping.

Works with ChatGPT, Claude, Gemini, Grok, Midjourney, Ideogram, Veo3 & Kling. 4.8★ on the Chrome Web Store.

Create An Account