NativeScript Blog

NativeScript 9.0 Released

Technical Steering Committee (TSC) November 18, 2025

NativeScript 9.0 advances to a native ES module runtime. Paving the way to also add first-class Vite support, multi-window abilities for iOS, richer UI primitives, DX improvements, plus alignment with the latest device capabilities.

With version 9, we're turning NativeScript into a first class native ES module runtime (Learn more about what ESM is here), introducing swappable bundlers with first-class Vite support, unlocking multi-window apps on iOS and introducing a brand new root primitive <SplitView /> providing ideal split container layouts. It also elevates <ListView /> up a notch with Sticky headers, Sectioned data, and an optional search bar, plus significantly improves developer experience by never terminating the runtime if an error occurs during development with an optional visual error display to make them clear if desired. All while also adding Android edge-to-edge to make your apps feel right at home on today's devices.

tl;dr — Updating to NativeScript 9.0

Note: Node 22 or higher is required.

Updating to any minor or major version of NativeScript starts with installing the latest CLI:

npm install -g nativescript

Confirm your installed version:

ns -v

You should see at least 9.0.0 or higher.

Then, from your app, run the migration:

ns migrate

This will update your project structure, runtime dependencies and configuration where possible.

Finally, clean your project:

ns clean

Note: the CLI is always backwards compatible, so it's recommended to run the latest CLI regardless of your current app version. Also, previously ns clean would clear your package-lock.json by default. In 9.0, the lock file is no longer cleared by default. You can configure nativescript.config.ts with cli.additionalPathsToClean if you still want that behavior.

Here are the dependencies you can expect to see after a successful 9.0 migration (exact versions may vary per template and framework):

"dependencies": {
  "@nativescript/core": "~9.0.0"
},
"devDependencies": {
  "@nativescript/android": "~9.0.0",
  "@nativescript/ios": "~9.0.0",
  "@nativescript/types": "~9.0.0",
  "@nativescript/webpack": "~5.0.0"
}

Note about v9 ES Module default output vs Commonjs bundling: While the latest @nativescript/webpack release defaults to es modules builds, you can switch to prior commonjs builds anytime by using the --env.commonjs flag.


Native runtime ES Module support

NativeScript 9.0 promotes ES modules (ESM) from “supported via bundlers” to first-class runtime citizens.

At a high level:

  • Both the iOS and Android runtimes now understand ESM directly.
  • .mjs bundles and chunks are detected and executed, while still supporting existing .js (CommonJS) bundles.
  • import.meta, dynamic import() and HTTP-loaded ESM realms (for dev/HMR) are now built into the runtime.
  • Error handling around module resolution and loading has been tightened up for better diagnostics.

Behind the scenes, the iOS runtime gained:

  • Conditional ESM vs CommonJS consumption depending on what your bundler outputs. This is handled automatically without you even thinking about it.
  • Dynamic import support for lazy loading and code-splitting.
  • More robust handling of external modules and HTTP-based module imports used during dev.

On Android, the runtime:

  • Detects .mjs vs .js and executes the right module format.
  • Implements ESM loading and callbacks natively (including import.meta and dynamic imports).
  • Extends Workers and the static binding generator (SBG) to understand .mjs code.

The result: your app code, your bundler and the NativeScript runtime all speak the same ES module language, whether you use Vite, Webpack, or any other bundler that emits ESM.


Swappable bundlers & first-class Vite support

NativeScript 9.0 introduces a swappable bundler story with Vite as a first-class option.

We've added a new @nativescript/vite package that:

  • Provides an integrated Vite-based bundler for NativeScript apps.
  • Handles vendor bundle generation and a manifest system for optimized dependency management.
  • Integrates tightly with the new HTTP ESM runtime to load modules on device.

Vite configs can live alongside existing Webpack configs, unlocking migration paths such as:

  • Start new apps with Vite anytime.
  • Incrementally experiment with Vite in existing apps while keeping Webpack available.

Getting started with Vite

Once you've migrated to 9.0 you can install the plugin and use the quick start init command.

npm install @nativescript/vite

Quick start (init)

To bootstrap an existing NativeScript app with Vite, you can first adjust your config.

1. Adjust nativescript.config.ts to use Vite

Make sure your nativescript.config.ts includes the following to use Vite as the bundler:

export default {
  // ...
  bundler: "vite",
  bundlerConfigPath: "vite.config.ts",
  // ...
};
2. Init the config

Now run from your app root:

npx nativescript-vite init

This will:

  • Generate a vite.config.ts using the detected project flavor (Angular, Vue, React, Solid, TypeScript, or JavaScript) and the corresponding helper from @nativescript/vite.
  • Add (or update) the following npm scripts in your app package.json:
    • dev:ios
    • dev:android
    • dev:server:ios
    • dev:server:android
    • ios
    • android
  • Add the devDependencies concurrently and wait-on.
  • Add the dependency @valor/nativescript-websockets.
  • Append .ns-vite-build to .gitignore if it is not already present.

You now have two ways to work with Vite:

  1. HMR workflow
npm run dev:ios
  1. Standard dev workflow (non-HMR)
ns debug ios --no-hmr
ns debug android --no-hmr

Note: You'll want at least Node 25+ for HMR development.

Documentation for @nativescript/vite can be found here.


Multi-window iOS apps

On iOS, NativeScript 9.0 unlocks true multi-window scene support.

Apps can now:

  • Opt into multiple scenes (windows) on iPad via the iOS 13+ windowing APIs.
  • Use UIScene lifecycle, as soon required, by all iOS apps—including macOS Catalyst apps.
  • Use multiple Frame / Page stacks coordinated across different windows.

From your app's perspective you get:

  • A clean API to register and manage scenes.
  • Events for when new windows are created, activated or discarded.
  • Compatibility with existing navigation patterns.

Refer to the iOS multi-window docs for details on how to enable and use multiple windows in your app.


New <SplitView /> for iOS

NativeScript 9.0 also adds a new SplitView primitive backed by UISplitViewController on iOS.

SplitView coordinates up to four column roles:

  • primary – main navigation or list view.
  • secondary – detail/content view.
  • supplementary – contextual content (filters, metadata, etc.).
  • inspector – optional tools/inspector column (iOS 17+ triple-column style or when available).

You declare each column as a child Frame so that each column maintains its own navigation stack while sharing a single split layout.

Example usage:

<SplitView displayMode="twoBesideSecondary" splitBehavior="tile"
           preferredPrimaryColumnWidthFraction="0.25"
           preferredSupplementaryColumnWidthFraction="0.33"
           preferredInspectorColumnWidthFraction="0.20">
  <Frame splitRole="primary" defaultPage="pages/master" />
  <Frame splitRole="secondary" defaultPage="pages/detail" />
  <Frame splitRole="supplementary" defaultPage="pages/context" />
  <Frame splitRole="inspector" defaultPage="pages/inspector" />
</SplitView>

SplitView also exposes events like inspectorChange, so you can react when certain panels are shown or hidden.

Refer to the SplitView docs for more details on configuration and usage.

This makes classic master-detail layouts, productivity tools, and complex iPad/macOS UIs much easier to build with NativeScript.


NativeScript's ListView now brings additional power features.

In 9.0 you get:

  • Sticky headers that remain pinned while scrolling through a section.
  • Sectioned data support, including section index metadata on item events.
  • An optional search bar that can auto-hide while you scroll.

Broadly applicable to many common user experience goals, this also pairs especially well with the new SplitView and multi-window layouts for classic master-detail workflows like mail clients, file browsers, or dashboards.


DX+ — Error handling that keeps the runtime alive

Developer experience has taken another step forward.

The iOS and Android runtimes now provide:

  • The adjustment for development-time errors to not tear down the entire runtime, letting you fix, save and continue.
  • Optional in-flight error displays with more verbose exception output and cleaned-up stack trace handling.

Combined with Vite's HMR and the HTTP-loaded ESM realms, this makes iterating on UI and logic significantly more forgiving—especially when you're exploring new APIs or refactoring larger codebases.

You can optionally enable in-flight error overlays via nativescript.config showErrorDisplay setting.


CLI hooks support ES Modules too!

A new guide has been added covering NativeScript CLI's powerful hooks infrastructure here:

NativeScript hooks are executable pieces of code or Node.js scripts that can be added by application or plugin developers to customize the execution of particular NativeScript commands. They provide the power to perform special activities by plugging into different parts of the build process of your application.

Additional iOS & UI goodies

Beyond the headline features, 9.0 ships a number of UI and iOS-specific enhancements that help polish your apps.

TabView iOS 26+ bottom accessory & minimize behavior

For devices on iOS 26+, TabView gains:

  • An optional bottom accessory view (iosBottomAccessory) that sits above the tab bar and can host custom content (buttons, toolbars, etc.).
  • Control over the tab bar's minimize behavior, including options like never, onScrollDown and onScrollUp.

This gives you modern tab bar experiences similar to the latest iOS system apps.

Glass effects & LiquidGlass containers (iOS / visionOS 26+)

We've added new glass effect containers and configuration:

  • Expanded GlassEffectConfig with spacing, animation duration, and a none variant.
  • New LiquidGlass and LiquidGlassContainer views that let you compose dynamic glassy surfaces.

These APIs target iOS and visionOS 26+, giving you a straightforward way to experiment with dynamic glass effects and bubbling animations in your UX.

Android edge-to-edge

Modern Android UIs expect content to extend edge-to-edge, gracefully handling status bars, navigation bars and device cutouts.

NativeScript 9.0 delivers an edge-to-edge system for Android that lets you opt in per view while giving you fine-grained control over insets.

Highlights:

  • New utilities like enableEdgeToEdge, setStatusBarColor, setNavigationBarColor and setDarkModeHandler exposed on @nativescript/core Utils. These help you:
    • Enable edge-to-edge on an activity.
    • Configure light vs dark status/navigation bar colors.
    • Handle dark mode transitions.
  • Layout support for overflow handling (androidOverflowEdge and androidOverflowInset) so you can decide which views consume system insets and how.
  • Defaults that avoid accidental content overlap while still enabling immersive UIs.

Refer to the docs on androidOverflowEdge and androidOverflowInset for details on how to enable and use edge-to-edge in your app.

Android navigation & system behavior

Alongside edge-to-edge, Android 9.0 work includes:

  • A new OnBackPressed handling aligned with Android's predictive back gesture APIs.
  • Internals updated to modern Gradle and Android build tool versions.
  • Test infrastructure improvements that better reflect real runtime behavior.

Your existing back button handlers continue to work, but apps targeting newer Android versions can now participate more naturally in the system's navigation UX.


Android 16KB page size

NativeScript 9.0 updates Android apps to use a 16KB page size for memory management.

We also rebuilt other plugins we manage to enable 16KB support as well.

If you need help updating your app(s)/lib(s), reach out to the community or contact any of our Partners for assistance.


TabView icon improvements

TabView now supports more flexible icon sources:

  • sys://... iconSource values for system icons.
  • font://... iconSource values for font-based icons, including support for iconFontFamily.

This makes it easier to standardize icon usage across tabs, with or without image assets.

Multiple CSS box-shadows

@nativescript/core now supports multiple CSS box-shadow values on a single view.

In addition:

  • Android shadows now respect transparent backgrounds without requiring overlay layers.
  • Android shadows render as solid when blur radius is <= 0.
  • Shadow blur values are tuned to match CSS expectations more closely across iOS and Android.

This gives you significantly more visual flexibility for cards, surfaces and elevated elements.


CSS direction for RTL/LTR support

NativeScript 9.0 adds support for the CSS direction property to control right-to-left (RTL) and left-to-right (LTR) layout direction at the view and application level.

At a high level:

  • You can set direction: ltr or direction: rtl on any view (or on the root layout) to enforce layout direction via the underlying native APIs.
  • The property is inherited, so setting it high in your view hierarchy will cascade to child views.
  • On iOS, RTL support is always available; on Android you enable it by adding android:supportsRtl="true" to the <application> tag in AndroidManifest.xml.

Enabling direction affects multiple parts of the UI automatically, giving you more predictable behavior for RTL languages:

  • Navigation & transitions
    • Standard slide transitions automatically reverse (slide to the right in RTL).
    • Standard flip transitions flip in the opposite direction when RTL is active.
  • Action bar & buttons
    • iOS navigation bars align the back button appropriately for RTL.
    • Button text alignment defaults are normalized so both platforms behave consistently.
  • Text and labels
    • Label default text alignment respects the current layout direction.
    • Text ellipsis positioning is updated so truncation dots render on the correct side based on direction.
  • Logical alignment values
    • horizontalAlignment now supports start and end in addition to left and right, so components can align logically with the active direction.
  • ScrollView and Flexbox layout
    • Horizontal ScrollView starting position respects RTL (scrollbar initially aligned to the end on iOS, matching Android behavior).
    • FlexboxLayout gains proper layout direction handling for flex alignment and flex-direction values.

A helper like hasRtlSupport is also available to detect whether RTL is enabled, which can be useful when you want to conditionally apply RTL-specific styling or logic.

Vision Pro CLI improvements

The NativeScript 9 CLI now includes support for building and preparing via ns build visionos --release/ns prepare visionos --release with Apple Vision Pro devices.


Security

NativeScript 9.0 includes several security sweeps including clearing all transient dependency vulnerabilities in the CLI, thanks to great collaboration within the OpenJS Foundation.

A minimum requirement of Node 22+ also helps ensure your development environment benefits from the latest security patches and improvements.


What's next after 9.0?

NativeScript 9.0 establishes critical groundwork for the next decade of the framework:

  • ES module-first runtimes.
  • Swappable bundlers with Vite as a first-class citizen.
  • Multi-window and advanced layouts on iOS.
  • A more expressive UI toolkit.

Looking ahead, the TSC will continue investing in:

  • @nativescript/foundation as an evolution of @nativescript/core.
  • Further Node-API engine work and cross-ecosystem interop.
  • Expanded Vite templates and tooling across all supported flavors.
  • Continuing to invest in DX improvements, documentation and community engagement.

We're excited to see what you build with 9.0 and beyond—please share your feedback, questions and experiments in the community Discord.


Join our Discord Community

📣 Join us and say Hello!

Need professional help with your projects?

Contact any of our Partners for assistance.

Thank you

We would like to thank our thoughtful community for their continuous input, contributions and support across Open Collective and GitHub Sponsors ❤️ In addition to our family throughout the OpenJS Foundation, without all of you, this release would not have been possible.

Join the conversation

Share your feedback or ask follow-up questions below.