Nuvaka › Developer docs

Nuvaka Apps developer documentation

Add your own app to Nuvaka General App: a UI built with HTML, CSS and JavaScript, an optional background script, and Nuvaka data (notes, cloud files, clipboard pool, mail…) to the extent the user allows. Users install your extension in the app from Apps › Store.

What Nuvaka Apps is

  • Package: an extension is a .nvx file (ZIP) with the nuvaka.json manifest at its root. Its ID has the form <your-username>.<name>, e.g. tarikgkhsn.faturaci, and never changes once published.
  • UI: an HTML page opened in a sandboxed frame (iframe). Every entry in the manifest's pages shows up in the Apps menu under the publisher heading. The app always shows an info bar above the frame (name, version, trust badge, publisher, Permissions, Stop).
  • Background: an optional single-file JavaScript module. It runs in the QuickJS engine, separately for each extension, and wakes up on schedules (every 15m, daily 09:00…) and events (app.started, notes.changed…).
  • The nuvaka object: the app injects a global nuvaka object into every frame and background script; no library needed. The @nuvaka/extension-sdk package only adds TypeScript types, typed error classes and a mock nuvaka for tests.
  • Permissions: an extension can only use what it asks for in its manifest and the user grants. Critical permissions such as mail, connection passwords and writing to Nuvaka files are confirmed again on every use. See Concepts.
  • Data: every extension gets its own key-value storage on the server (no permission needed, quota up to 100 MB). It syncs across devices and every write carries the version it read (MVCC).
  • Platforms: extensions currently run in the desktop app (Windows, Linux, macOS).

Your first extension in 10 minutes

You need Node.js 20 or newer, a Nuvaka account with a verified email and the desktop app.

  1. Scaffold
    npm create @nuvaka/extension hello -- --username your-username --ui --background
    cd hello
    npm install

    --username is your Nuvaka username; the ID becomes your-username.hello. Created files: nuvaka.json, icon.svg, index.html, app.js, style.css, background.js, test/extension.test.js, package.json. Without --ui or --background you get both.

  2. Check
    npx nuvaka-ext lint

    The same rules the server applies on upload: manifest schema, file types, forbidden code patterns, and whether the nuvaka.* namespaces used in code match the permissions. Details: Security rules.

  3. Try it in the app

    In the app, open Profile and, on the Profile tab under Developer, tick Developer mode. Then use Apps › Manage apps › Load from folder and pick your extension folder. The folder runs unsigned and only on this device; its version shows as dev and every permission in the manifest counts as granted. After a change, use the Reload button in the list.

    npx nuvaka-ext dev

    dev watches the folder and runs lint on every change. If you run the app from source (debug build), it also prints the NUVAKA_EXT_DEV_DIR command that loads the folder at startup.

    Server endpoints need an install

    In an extension loaded from a folder, local capabilities work (UI, net, files, local clipboard, ui.notify). Server endpoints such as storage, notes, clipboard pool and push only work if the extension is installed on your account: publish a version and install it to try them.

  4. Get a developer token and sign in

    Create a token under Profile › Developer › Developer tokens (starts with nvd_, shown once, valid for 1 year).

    npx nuvaka-ext login --token nvd_xxxxxxxx
    npx nuvaka-ext whoami
  5. (Recommended) Publisher signing key
    npx nuvaka-ext keys create

    Add the printed public key under Profile › Developer › Publisher signing keys. From then on every upload must be signed; even a stolen token cannot publish a version without the key.

  6. Publish
    npx nuvaka-ext publish --changelog "First version"

    The result is published, review or rejected. A publisher's first extension goes to review; once approved it appears in the Store. See Publishing and review.

  7. Install

    Find your extension in Apps › Store and install it. The install syncs to all devices on your account.

First code

In the UI, nuvaka.ready resolves once the shell connects and gives you the context (page, locale, theme). Frames have no localStorage; use nuvaka.storage for persistent data.

// app.js (UI)
const out = document.getElementById('count')

nuvaka.ready.then(async () => {
  const r = await nuvaka.storage.get('count')      // { value, version } | null
  out.textContent = r ? r.value : 0
})

document.getElementById('inc').onclick = async () => {
  // Read → modify → write with the version read; retries with the current value if another device got in between
  const r = await nuvaka.storage.update('count', (n) => (n || 0) + 1)
  out.textContent = r.value
}

// Another device or the background wrote (only newer versions arrive)
nuvaka.storage.onChanged((key, c) => { if (key === 'count' && !c.deleted) out.textContent = c.value })
// background.js (QuickJS; single file, no imports)
nuvaka.on('schedule', async ({ schedule, at }) => {
  await nuvaka.ui.notify('Hello', `Scheduled task ran (${schedule})`)
})

Documentation

Versions

These docs cover API v1; the manifest says "apiVersion": 1. A breaking change comes with a new API version. The major version of the @nuvaka/extension-cli and @nuvaka/extension-sdk packages is the API version they support (1.x = API v1).

Nuvaka Apps API v1 · last updated 2026-09-27