$ ls ./menu

© 2025 ESSA MAMDANI

LIVE
Fable 5.1 vs Gemini 3.8 Flash vs Muse Spark 1.3 vs GPT-6 Astra: AI Models Early September 2026GPT-6 Astra Safety: The Most Powerful Model Needs New GuardrailsGPT-6 Astra Turns AI Agents Into Digital CoworkersGPT-6 Astra and AGI: How Close Are We, Really?GPT-6 Astra: The Frontier Model That Changes the Agent EquationMuse Spark 1.3: Meta’s Frontier Coding AgentFable 5.1 vs Gemini 3.8 Flash vs Muse Spark 1.3 vs GPT-6 Astra: AI Models Early September 2026GPT-6 Astra Safety: The Most Powerful Model Needs New GuardrailsGPT-6 Astra Turns AI Agents Into Digital CoworkersGPT-6 Astra and AGI: How Close Are We, Really?GPT-6 Astra: The Frontier Model That Changes the Agent EquationMuse Spark 1.3: Meta’s Frontier Coding AgentFable 5.1 vs Gemini 3.8 Flash vs Muse Spark 1.3 vs GPT-6 Astra: AI Models Early September 2026GPT-6 Astra Safety: The Most Powerful Model Needs New GuardrailsGPT-6 Astra Turns AI Agents Into Digital CoworkersGPT-6 Astra and AGI: How Close Are We, Really?GPT-6 Astra: The Frontier Model That Changes the Agent EquationMuse Spark 1.3: Meta’s Frontier Coding AgentFable 5.1 vs Gemini 3.8 Flash vs Muse Spark 1.3 vs GPT-6 Astra: AI Models Early September 2026GPT-6 Astra Safety: The Most Powerful Model Needs New GuardrailsGPT-6 Astra Turns AI Agents Into Digital CoworkersGPT-6 Astra and AGI: How Close Are We, Really?GPT-6 Astra: The Frontier Model That Changes the Agent EquationMuse Spark 1.3: Meta’s Frontier Coding Agent
cd ../blog
9 min read
Developer Tools

ScriptC Compiles TypeScript for iOS and Android

> Learn how ScriptC compiles TypeScript to native iOS and Android libraries, with architecture, setup, limits, performance, security, and integration guidance.

ShareXLinkedIn

🎧 Listen — ~9 min

Ready · ScriptC Compiles TypeScript for

0:00 / 9:00
ScriptC Compiles TypeScript for iOS and Android
Verified by Essa Mamdani

What Is ScriptC?

ScriptC is often described as a new mobile programming language that runs on both iOS and Android. That description is only partially correct. ScriptC is an experimental compiler that turns ordinary TypeScript into native executable code or native library archives. Its goal is to produce small, fast native programs without requiring Node.js, the V8 runtime, or a node_modules directory at runtime.

The most important point is that ScriptC does not create a new TypeScript dialect. Developers write regular TypeScript, the TypeScript compiler handles parsing and type checking, ScriptC generates LLVM IR, and clang produces the target-native output. When code cannot be statically compiled, ScriptC does not silently translate it incorrectly. It either reports a diagnostic or, after an explicit --dynamic opt-in, uses an embedded JavaScript engine.

For mobile developers, another distinction matters: iOS and Android support currently means library-mode support, not standalone app generation. ScriptC produces static archives for both platforms. The final application remains an Xcode project or an Android Gradle/NDK project, which links and calls the ScriptC-generated library.

ScriptC’s Compilation Architecture

ScriptC is easiest to understand as a three-tier compilation system.

Tier 1: Static native compilation

In the default mode, supported TypeScript is compiled into native code. Classes, closures, async/await, the standard library, and supported Node APIs are lowered against a native runtime. The resulting program does not need Node.js, V8, or a full JavaScript engine at runtime.

This model is especially attractive for deployment. According to the official quickstart, a hello-world binary can be approximately 320 KB and start within a few milliseconds, while a comparable Node program needs a much larger runtime footprint. Exact size depends on the program, linker, optimization settings, and target, so these numbers should be treated as reference measurements rather than universal guarantees.

Tier 2: Explicit dynamic execution

For npm dependencies or code that relies heavily on any, ScriptC provides the --dynamic option. In this mode, a QuickJS-based JavaScript engine is embedded into the binary. Dependencies are embedded during the build, so the executable does not need to read a node_modules directory at runtime.

This improves compatibility, but it can reduce the benefits of pure native compilation. JavaScript executed inside the dynamic island may be slower than statically compiled code, and only supported Node built-ins or shims should be assumed to work. For that reason, --dynamic is best treated as a measured compatibility escape hatch rather than a default strategy.

Tier 3: Compile-time rejection

Constructs that cannot be handled by either the static tier or a safe dynamic boundary are rejected during compilation. ScriptC reports a specific SC error code, a code frame, and often a rewrite suggestion.

This behavior is useful in production systems. A build failure with a precise diagnostic is safer than silent miscompilation. It also means that porting an arbitrary TypeScript project to ScriptC without changes is not a realistic assumption.

The Actual iOS Support Model

ScriptC documents the aarch64-apple-ios target for iOS devices and aarch64-apple-ios-simulator for the iOS simulator. Both targets produce arm64 static archives. The official platform documentation lists iOS 15.0 as the minimum supported version.

Building for iOS requires a macOS host and the appropriate Xcode iPhoneOS or iPhoneSimulator SDK. This is expected because the archive must be produced with Apple SDK headers, the Mach-O format, and Apple platform linker details.

A conceptual device build looks like this:

bash
1SCRIPTC_CC=zigcc \
2SCRIPTC_TARGET=aarch64-apple-ios \
3scriptc build --lib --profile app.profile.json

For the simulator, change the target:

bash
1SCRIPTC_CC=zigcc \
2SCRIPTC_TARGET=aarch64-apple-ios-simulator \
3scriptc build --lib --profile app.profile.json

The important concept is --lib. If a developer tries to produce a normal standalone executable for an iOS target, ScriptC rejects the operation because the mobile application executable is owned by the host Xcode project. ScriptC’s output is linked into that application as a static library.

This does not mean ScriptC replaces Swift or UIKit. UI lifecycle, navigation, permissions, background modes, push notifications, App Store packaging, and Apple framework integration remain responsibilities of the host iOS application. ScriptC is more appropriate for shared business logic, deterministic computation, parsing, rules engines, or a native library layer.

The Actual Android Support Model

For Android, ScriptC uses the aarch64-linux-android target to produce an arm64 static archive. Android builds use the NDK’s bionic headers, and the documented minimum API level is 26. The embedding project should therefore use a minSdkVersion of 26 or higher.

The Android target is not limited to macOS. The official documentation requires the Android NDK and describes discovery through the Android SDK setup or ANDROID_NDK_ROOT, depending on the environment.

A conceptual build command is:

bash
1SCRIPTC_CC=zigcc \
2SCRIPTC_TARGET=aarch64-linux-android \
3scriptc build --lib --profile app.profile.json

The generated archive can be linked into an Android Gradle/NDK project. The host application can call the library through JNI or another declared ABI entry point. Java/Kotlin UI, the Android lifecycle, permissions, and platform services remain inside the Android project.

There is an important compatibility limitation. The documented primary path is arm64; teams should separately verify support for x86 emulators, x86_64 devices, or additional ABIs against the current ScriptC target matrix and their NDK configuration. “Android supported” should not be interpreted as universal APK or ABI coverage.

The Profile and Embedding Boundary

In library mode, ScriptC uses a profile to define exported functions, callbacks, and runtime behavior. The profile describes which functions the host application can call and how the native library should be integrated.

A useful mental model is:

diagram

Host callbacks and ABI symbols allow the native application to invoke ScriptC code. ScriptC documents multi-instance and thread-instanced profiles, but production use requires explicit tests for ownership, thread affinity, initialization, shutdown, and callback lifetimes.

This model is different from Flutter or React Native. Flutter provides its own UI rendering engine and widget runtime. React Native provides a JavaScript-to-native component model and bridge. ScriptC’s primary product is not a UI framework; it is a compiled TypeScript library and runtime boundary.

Build a Desktop Prototype First

Before attempting mobile integration, it is safer to test the logic on macOS, Linux, or Windows. Typical prerequisites include:

  • Node.js 20 or newer for running the compiler.
  • Clang and the Xcode Command Line Tools on the primary macOS path.
  • Zig and the relevant SDK or NDK for cross-target builds.
  • TypeScript that stays within ScriptC’s supported type and standard-library surface.

Install ScriptC:

bash
1npm install -g scriptc

Create hello.ts:

ts
1const who: string = process.argv.length > 2
2  ? process.argv[2]
3  : "world";
4
5console.log(`hello, ${who}`);

Run it directly:

bash
1scriptc run hello.ts

Build a standalone executable:

bash
1scriptc build hello.ts -o hello
2./hello scriptc

Inspect static coverage:

bash
1scriptc coverage hello.ts

The coverage command is central to porting decisions. It helps identify which statements compile statically, which sites require the dynamic engine, and which constructs are compile blockers.

TypeScript Syntax Does Not Guarantee Identical Semantics

ScriptC looks like TypeScript, but its type system and runtime semantics are constrained by native compilation. JavaScript patterns that are normal in Node.js or a browser can become traps or diagnostics in ScriptC.

Dense-array behavior is one example. An out-of-bounds array access may trap at runtime instead of returning undefined. This pattern is therefore risky:

ts
1const who = process.argv[2] ?? "world";

An explicit bounds check is safer:

ts
1const who = process.argv.length > 2
2  ? process.argv[2]
3  : "world";

The any type can also produce a compile error in the default static mode. Developers may need to use unknown with a checked cast or intentionally enable --dynamic. Some standard-library methods, complex unions, generic dispatch patterns, and unsupported regular-expression or collection APIs can also produce SC diagnostics.

The correct migration workflow is therefore not “run the compiler and hope.” Use the coverage report, compiler diagnostics, and differential tests together.

Performance and Binary-Size Expectations

ScriptC’s strongest value proposition is its deployment shape: native output, fast startup, no Node runtime, and an optional dynamic engine. These characteristics can matter for CLI tools, local workers, embedded rules engines, and small backend utilities.

Mobile performance needs more careful evaluation. Compiling TypeScript logic into a native archive can improve startup or CPU-heavy paths, but the final application’s performance depends on much more than the compiler. JNI or ABI calls, memory copies, platform callbacks, UI rendering, and I/O boundaries may become the bottleneck.

A meaningful benchmark plan should compare:

  • The same algorithm in a ScriptC static archive and a Kotlin or Swift implementation.
  • One large cross-boundary call versus thousands of small calls.
  • Cold start time and archive size.
  • Memory retention and multi-instance behavior.
  • Debug and release builds.
  • An arm64 physical device, simulator or emulator, and a representative lower-end device.

The word “native” is not an automatic performance guarantee. The boundary design matters just as much as the compiler output.

Security and Supply-Chain Considerations

With --dynamic, npm package JavaScript is embedded into the executable. This can make deployment more reproducible because the runtime no longer needs the package directory. However, it does not eliminate build-time supply-chain risk. Version pinning, lockfile review, provenance, license checks, and source audits are still necessary.

In library mode, keep the ABI surface as small as possible. Every exported function becomes a compatibility contract with the host application. Validate inputs, document buffer ownership, define callback thread rules, and never cast untrusted data directly into native structures.

ScriptC’s documented limitations also state that foreign native callbacks may be asynchronous and should not be treated as real-time synchronous callbacks. This makes the boundary risky for audio processing, hard real-time control, or code that requires a library-thread synchronous return.

Which Projects Are a Good Fit?

ScriptC is worth evaluating when:

  • You want to package TypeScript logic as a small native binary or embedded library.
  • The same deterministic business rules must be shared across iOS and Android.
  • The UI can remain native Swift or Kotlin.
  • The team can maintain compiler diagnostics and target-specific integration.
  • Startup time, binary footprint, or no-runtime deployment is important.

It is currently a poor fit when:

  • You are looking for a complete cross-platform UI framework.
  • You need the entire npm ecosystem without porting work.
  • The project must support older iOS versions or Android API levels below 26.
  • You need arbitrary JavaScript reflection, dynamic loading, or V8-compatible behavior.
  • The team cannot test macOS/Xcode and Android NDK integration.

Final Verdict

ScriptC is interesting because it moves TypeScript toward a “compile to native code and make dynamic behavior explicit” model instead of the traditional “ship JavaScript with a runtime” approach. Its iOS and Android support is real, but describing it as a direct Flutter or React Native replacement would be technically inaccurate.

The most practical way to understand ScriptC today is as a cross-platform native logic-library compiler. For iOS, it produces arm64 static archives using the Xcode SDK. For Android, it produces arm64 archives using the Android NDK with API level 26 as the documented minimum. The final application, UI, lifecycle, and platform APIs remain inside the host project.

The best adoption strategy is to start with a small pure-TypeScript module such as validation, pricing rules, document parsing, or offline computation. Compile it on the desktop, inspect the static surface with scriptc coverage, compare Node and native behavior with differential tests, and then integrate the library into an iOS simulator build and an Android emulator build. Consider production rollout only after the boundary is stable and benchmarks show a measurable benefit.

Official References

Keep reading

#ScriptC#TypeScript#iOS Development#Android Development#Native Compilation#Cross-Platform Development
ShareXLinkedIn

⚡ Daily AI Model Drop — Get Kimi K3 benchmarks before Twitter

Join 2,400+ AI engineers. 1 email/day, no spam, unsubscribe anytime

Comments