AbsoluteJS

Native Apps

Every AbsoluteJS app is also an iOS and Android app. Add a mobile block to absolute.config.ts and the pages you have already written ship to the App Store and Google Play: the same routes, the same server and the same code.

#One config

Three fields make an app: its store identifier, its name and the server it talks to.

TS
import { defineConfig } from '@absolutejs/absolute';

export default defineConfig({
  mobile: {
    appId: 'com.example.shop',
    appName: 'Shop',
    server: { productionOrigin: 'https://shop.example.com' }
  }
});
BASH
bunx absolute mobile init   # create the iOS and Android projects
bun dev                     # web, plus your app on an emulator or simulator
Before your first store release
Add your Apple team prefix and Android signing fingerprint under deepLinks. Your server publishes the files that link your domain to the app, and a production server will not start without them. Branding & deep links covers both.

#What you get

AbsoluteJS looks at what your app already uses and sets up the native side to match. Install @absolutejs/auth and the app signs in; install @absolutejs/sync and it works offline; import camera and the camera plugin and its permission prompts are added.

Your pages, as screensEvery page route you already serve with a React, Svelte, Vue, Angular, HTML or HTMX handler is found at build time and packaged into the app.
Sign-inWith @absolutejs/auth installed, the app signs in through the system browser and keeps its credentials in the Keychain or Android Keystore. Page code does not change.
Offline dataWith @absolutejs/sync installed, data is stored encrypted on the device, writes queue offline, and the OS syncs in the background.
Device featuresCamera, photos, location, notifications, share, haptics, clipboard, files and more, through one API. Only the plugins you import are installed.
Push notificationsAPNs and FCM registration is automatic, and the same code sends Web Push to the browser and installed web app.
Deep linksUniversal links and Android app links open the right screen, and the association files are served by your server.
Over-the-air updatesShip signed fixes without a store review, rolled out in stages and rolled back automatically if a release fails to start.
Store releasesSigned App Store and Google Play builds, a release check, store publishing and a generated GitHub Actions workflow.

#How it works

1
Generate the native projects
absolute mobile init generates the iOS and Android projects, installs the pinned native packages and applies your config: icons, deep links, permissions.
2
Package your pages
The build finds the page routes on your Elysia server and packages each page’s client code and styles into the app. Nothing is loaded from a remote URL.
3
Fetch each page’s data
The app launches with no network. When it opens a route, it asks your production server for that page’s props as JSON from the same handler that renders the page for the web.
4
Render on the device
The packaged page renders those props on the device. Links, Back and deep links navigate inside the app.

Because the interface ships inside the app, it starts instantly and offline. Each page asks your server for fresh data when it opens; data that must be there offline lives in @absolutejs/sync. When you deploy a new server, apps already installed keep working: the server keeps answering the three most recent releases, kept in a blob store or your build directory, and asks for an update only when an installed app is older than that. How it works has the details.

#Same code everywhere

Device features come from @absolutejs/devices. The build picks the right implementation for the browser, iOS or Android, so your page never checks which one it is running on. This function takes a photo with the native camera in the app and through the browser on the web:

TS
import { camera, haptics } from '@absolutejs/devices';

const takeReceiptPhoto = async () => {
  const permission = await camera.requestPermission();
  if (permission.state !== 'granted') return null;

  await haptics.impact('light');

  return camera.takePhoto({ direction: 'rear' });
};

#Capacitor or Expo

Apps are built with Capacitor unless you choose otherwise, and that is the right choice for almost every app. Expo is there for teams that need specific screens in React Native: very long lists, gesture-heavy interfaces, native stack transitions, or a library that only exists for React Native. You keep every other page as it is. Expo explains when it pays off.

FeatureCapacitor (default)Expo
Every page in every supported framework
Screens written in React Native
Expo routes you choose can be React Native components; every other route stays your AbsoluteJS page.
Native projectCommitted, editable mobile/Generated, never edited
Device features, Auth, Sync and push
Signed over-the-air updates
Best forEvery appScreens that need native UI

#Frameworks

Pages written inCapacitorExpo
React
Svelte
Vue
Angular
HTML
HTMX
hx-get, hx-post and form actions are pointed at your production server.
EmberComing soonComing soon
AstroComing soonComing soon

#Platforms

PlatformBuild onSetup
AndroidLinux, macOS, Windows or WSLabsolute mobile doctor android --fix installs the SDK, emulator and Java 21
iOSmacOS with Xcode, or any machine with a paired Macabsolute mobile pair mac builds and runs on a Mac over SSH
bunx absolute mobile doctor
$ bunx absolute mobile doctor
Checks the Android SDK, emulator, Java and Xcode, and says what is missing.

#Packages

Native support is part of @absolutejs/absolute. These packages provide the parts your pages call, and the build installs the versions it needs.

#Where next