Build performant, native and cross-platform desktop applications with native Svelte + powerful CSS-like styling.🚀

  • By NodeGui
  • Last update: Nov 27, 2022
  • Comments: 16

Svelte NodeGUI

Join the NodeGUI community on Spectrum Join the Svelte community on Discord All Contributors JS Party #96

Build and Test status

Build performant, native and cross-platform desktop applications with Node.js and Svelte. 🚀

Svelte NodeGUI is powered by Svelte and Qt5 💚 which makes it CPU- and memory-efficient when compared to Chromium-based solutions like Electron. Svelte NodeGUI is essentially a Svelte renderer for NodeGUI.

If you are looking for the React-based version, check out: React NodeGUI.

If you are looking for the Vue-based version, check out: Vue NodeGUI.

Visit: for docs.


How does it look?

demo_linux demo_win demo_mac

More screenshots?

More Examples:


  • 🧬 Cross platform. Should work on major Linux flavours, Windows and macOS.
  • 📉 Low CPU and memory footprint. Current CPU stays at 0% on idle and memory usage is under 20 MB for a Hello World program.
  • 💅 Styling with CSS (includes actual cascading). Also has full support for Flexbox layout (thanks to Yoga).
  • ✅ Complete Node.js api support (Currently runs on Node v12.x - and is easily upgradable). Hence has access to all Node.js-compatible npm modules.
  • đŸŽȘ Native widget event listener support. Supports all events available from Qt / NodeJs.
  • 💾 Can be used for Commercial applications.
  • đŸ•”ïžâ€â™‚ïž Good Devtools support.
  • 📚 Good documentation and website.
  • đŸ§™â€â™‚ïž Good documentation for contributors.
  • đŸŠčđŸ»â€â™€ïž Good support for dark mode (Thanks to Qt).
  • 🏅 First class TypeScript support. (Works on regular JS projects too 😉 ).

Getting Started

Docs for contributing

Svelte NodeGUI

File issues and get in touch (e.g. on the Svelte Discord's #nativedev channel), and we can guide you to something broken that needs fixing!


Looking to contribute to NodeGUI? If you wish to implement a new widget/add more features and need help understanding the codebase, you can start here: Contributing developer docs.

Please read


npm run build

Optionally set QT_INSTALL_DIR='/path/to/qt' environment variable to build using your own version of Qt.

Updating docs

Generating docs from source code

The docs generation process is currently a manual operation (text edit everything yourself). The docs are a copy-paste of the React NodeGUI docs, with some text replacement. We're also carrying around a slight fork of the React NodeGUI source in the codebase. In future we hope to clean up this workflow and make it more automatable using typedoc just like the original React NodeGUI workflow.

Deploying docs to GitHub Pages

cd website && GIT_USER=<your_git_username> npm run deploy


As no funding infrastructure is in place for Svelte NodeGUI specifically, please consider supporting NodeGUI instead, which would be just as productive!

Special Thanks

Code of Conduct



Maintainers ✹

People maintaining this project.

Jamie Birch
Jamie Birch

Contributors ✹

Thanks goes to these wonderful people (emoji key):

Jamie Birch


Saurav Sahu




Jonas Grunert




This project follows the all-contributors specification. Contributions of any kind welcome!



  • 1


    Svelte NodeGUI literally uses React NodeGUI under-the-hood so I'm somewhat tempted to just point users at that docs site and call it a job done; but at the same time, people like things in one place. Wondering whether there's a low-effort way to move forwards on this?

    CC @a7ul

  • 2

    Fish shell

    This doesn't seem to work for me using fish, I had to switch to bash. While this isn't a problem it would be nice to support it.

    OS: Manjaro Linux Fish: 3.2.1 Node: 12 (latest) Node gui: Starter template

  • 3

    Rendering Breaks if User Components Used


    • Rendering breaks if App.svelte used user components (e.g: StepOne.svelte & StepTwo.svelte in starter template). Please, refer to for image.
    • This started from @nodegui/[email protected]. The most recent version @0.1.2 isn't fixing this.
    • The last version tested to work without breaking the rendering is @nodegui/[email protected]

    Test Platform:

    • Linux LMDE 4
    • node.js/qode v16.7.0 & v14.17.5
  • 4

    Gibberish main window

    The first time I do npm start, the attached screenshot is the window I see. This is on MacOS 11.6.

    I did have some other problems getting it running at all for the first time. I was able to get past them, but I am mentioning them here in case they're related. The first is described at this link, which was resolved by following the "Try the following" comment at the bottom of the linked page. The other was resolved by doing export NODE_OPTIONS=--openssl-legacy-provider.

    I'm no longer concerned about those earlier problems, but obviously, the screenshot shows a serious current problem.

    svelte-nodegui main window

  • 5

    add scrollArea

    No more exceptions, but... There are string components sizing issues (see demo) scrollArea has no size by default (has to be set manually) text block inside the scroll area is very small and does not seem to be resizable :-(

  • 6

    AllContributors bot hasn't made PR to update README

    Just spotted this. Although AllContributors is installed as an action (established in #18), it hasn't made a PR to fill out the table of contributors in the README (which I'd have expected to sync up with the .all-contributorsrc that I've written here). I'm not sure how to force it to update.

    Maybe now that it's public for the first time, we should make a whitespace-only edit to that file and see if the integration picks it up.

  • 7

    Possible need for a preprocessor


    It performs the following transforms to provide a better developer experience when using Svelte-Native:

    • [x] Adds <svelte:options namespace="xmlns" /> to the component, ensuring the generated code is compatible with svelte-native
    • [x] Changes bind:text="{email}" to text="{email}" on:textChanged="{e => email = e.value}"

    We at least need the namespace aspect, as if PR lands, we'll require such preprocessing in order to close

    I'm unsure whether we'll need it for bind:text; I haven't yet tried that feature (and indeed may not be able to if event listener names are forced to lower case – though I'm not sure of the casing used by NodeGUI yet).

  • 8

    How to fetch data with an async call ?


    I'm struggling at making a simple thing work : async data fetch. The documentation ( explains how to write a function that make this async call, but not how to call it.

    I've tried calling this async function directly in the (async) event handler of a button but the app crashes with FATAL ERROR: v8::HandleScope::CreateHandle() Cannot create a handle without a HandleScope.

    If I try to use svelte await blocks like this :

    <script lang="ts">
        import { onMount } from "svelte";
        import type { NSVElement, RNWindow } from "@nodegui/svelte-nodegui";
        import { Direction } from "@nodegui/nodegui";
        import fetch from "node-fetch";
         * The exact type for this is: NSVElement<RNWindow>
         * ... However, the Svelte language tools erroneously expect all bind:this values to extend HTMLElement, so
         * for now, we have to rely on reasserting the type.
        let win;
        let urlWidget;
        let dataPromise = loadData("");
        function loadPressed(){
            dataPromise = loadData(urlWidget.textContent);
        async function loadData(url){
                let response = await fetch(url);
                let jsonResponse = await response.json();
                return jsonResponse;
        onMount(() => {
            (window as any).win = win; // Prevent garbage collection, otherwise the window quickly disappears!
            (win as NSVElement<RNWindow>);
            return () => {
                delete (window as any).win;
        windowTitle="Seafile Share link DL">
        <view class="vertical">
            <view class="horizontal">
                <text>Share link url:</text>
                <lineEdit id="lineEdit" bind:this={urlWidget}/>
                <button text="Load" on:clicked={loadPressed}/>
                {#await dataPromise}
                    <text>Nothing loaded</text>
                {:then data}
                {:catch error}
         * CSS has a few gotchas for now.
         * 1) Some values need to be enclosed with quotes (e.g. `width: '100%';` rather than `width: 100%;`).
         *    See:
         * 2) Classes are not supported yet; they're a bit weird in Qt5.
         * 3) You can't write element-level rules like `text { color: 'red'; }`, unless they're global (not scoped).
         *    For scoped rules, you have to refer to the underlying native element, e.g. `QLabel { color: 'red'; }`.
         *    See:
            flex-direction: column;
            flex-direction: row;
            flex: 1;

    then I get a UnhandledPromiseRejectionWarning: ReferenceError: __awaiter is not defined...

    What is the correct way to do ?

  • 9

    feat: add sample app - file share

    This is a file share app to share file on local network. Should partly close #17

    I'm having trouble with Svelte's reactivity. And not sure if it's svelte or our renderer. @shirakaba Can you take a look? When I drop a new file, a text still shows the old file path.

  • 10

    Adds element with React NodeGUI interface

    @shirakaba I followed your advice from our previous discussion and came up with this! I initially had some troubles testing this because I hadn't bulit a library from src and used it in a project before.

    But now I see it works as expected: image

  • 11

    (#if, #each, and #await blocks not working fully) Issue updating text nodes: "addChild() called on an element that doesn't implement nodeOps.remove() [ undefined ]"

    Found in

    1. If you wrap the whole {#await}...{/await} block with an {#if dataPromise}, the enclosed text elements fail to update, with reasons relating to the next point.
    2. The console is spamming addChild() called on an element that doesn't implement nodeOps.remove() [ undefined ]. This is something to do with updating the child text nodes passed into the <text> element. That's a bug with the text-updating logic, though somehow we get away with it in this example. I'll track it.
  • 12

    Error on first run

    After fighting with cmake and the compile step, this is now the error message I get:

    PS G:\dev\svelte-nodegui-starter> npm run dev

    [email protected] dev

                            throw new TypeError(
    TypeError: The 'compilation' argument must be an instance of Compilation
        at NormalModule.getCompilationHooks (G:\dev\svelte-nodegui-starter\node_modules\webpack\lib\NormalModule.js:179:10)
        at G:\dev\svelte-nodegui-starter\node_modules\webpack\lib\HotModuleReplacementPlugin.js:752:18
        at Hook.eval [as call] (eval at create (G:\Dev\svelte-nodegui-starter\node_modules\webpack\node_modules\tapable\lib\HookCodeFactory.js:19:10), <anonymous>:102:1)
        at Hook.CALL_DELEGATE [as _call] (G:\Dev\svelte-nodegui-starter\node_modules\webpack\node_modules\tapable\lib\Hook.js:14:14)
        at G:\Dev\svelte-nodegui-starter\node_modules\webpack\lib\Compiler.js:1035:29
        at Hook.eval [as callAsync] (eval at create (G:\Dev\svelte-nodegui-starter\node_modules\webpack\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:6:1)
        at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (G:\Dev\svelte-nodegui-starter\node_modules\webpack\node_modules\tapable\lib\Hook.js:18:14)
        at Compiler.compile (G:\Dev\svelte-nodegui-starter\node_modules\webpack\lib\Compiler.js:1030:28)
        at G:\Dev\svelte-nodegui-starter\node_modules\webpack\lib\Watching.js:132:19
    Node.js v18.12.1
    PS G:\dev\svelte-nodegui-starter>

    Websearching talks about webpack, but nothing with high enough confidence to try anything with it.

  • 13

    Layout failing with user components

    Root cause issue for:

    • #65
    • #68
    • #70

    After a lot of red herrings involving Node version, environment, nodegui version, qode version, shell, custom elements, etc., I think I finally understand what's going on.

    v0.0.3-alpha.1 was the last release in which the starter template's layout was seen to be correct. However, in that release, {#each} and {#if} blocks didn't work correctly. So I merged the PR #60 in v0.0.4, changing how child elements were inserted, which seemed to fix that problem in all cases. Unfortunately, this PR brought an unnoticed regression in more complex UIs like that of the starter template.

    So this is problematic. We don't want to roll back to the DOM algorithm used in v0.0.3-alpha.1 because it has a subtle problem that stops {#each} and {#if} blocks working. We also can't stick with the approach used since v0.0.4 (still used in the version at the time of writing,v0.1.2), because it has obvious layout issues.

    Fixing {#each} and {#if} behaviour was a horribly subtle problem to solve, so I think the way forward is to stick with this current DOM model (rather than rolling back to the old DOM model) and try to fix this obvious layout problem.

  • 14

    Module not found: Error: Can't resolve '@nodegui/svelte-nodegui'

    The example starter won't work. OSX. v11.5.1, m1. Node v.16.3.0

    git clone
    cd svelte-nodegui-starter && npm install && npm run dev
    Run `npm audit` for details.
    ❯ npm run dev
    > [email protected] dev
    > webpack --mode=development
    asset nodegui_core-03615e63696900d1383da152cd3c5c85.node 7.28 MiB [emitted] (auxiliary name: main)
    asset index.js 1.39 MiB [emitted] (name: main) 1 related asset
    asset 08ef36629f2fe40bdcbe135ae303d949.jpg 58.1 KiB [emitted] [immutable] [from: assets/nodegui.jpg] (auxiliary name: main)
    runtime modules 21.9 KiB 10 modules
    modules by path ./node_modules/@nodegui/nodegui/ 510 KiB 212 modules
    modules by path ./node_modules/postcss/lib/*.js 479 KiB 25 modules
    modules by path ./node_modules/source-map/ 99.4 KiB 11 modules
    modules by path ./src/ 10.8 KiB
      modules by path ./src/components/ 6.85 KiB 3 modules
      2 modules
    modules by path ./node_modules/cuid/ 2.88 KiB 4 modules
    modules by path ./node_modules/webpack/hot/*.js 3.75 KiB 3 modules
    modules by path ./node_modules/chalk/ 12.1 KiB 3 modules
    modules by path ./node_modules/color-convert/*.js 20.3 KiB 3 modules
    modules by path ./node_modules/svelte/ 54.1 KiB
      ./node_modules/svelte/internal/index.mjs 53.9 KiB [built] [code generated]
      ./node_modules/svelte/index.mjs 212 bytes [built] [code generated]
    18 modules
    ERROR in ./src/app.ts 1:0-56
    Module not found: Error: Can't resolve '@nodegui/svelte-nodegui' in '/Users/def/Documents/Projects/sveltekit-todo-nodegui/nodetest1/svelte-nodegui-starter/src'
    resolve '@nodegui/svelte-nodegui' in '/Users/def/Documents/Projects/sveltekit-todo-nodegui/nodetest1/svelte-nodegui-starter/src'
      Parsed request is a module
      using description file: /Users/def/Documents/Projects/sveltekit-todo-nodegui/nodetest1/svelte-nodegui-starter/package.json (relative path: ./src)
        resolve as module
          /Users/def/Documents/Projects/sveltekit-todo-nodegui/nodetest1/svelte-nodegui-starter/src/node_modules doesn't exist or is not a directory
          looking for modules in /Users/def/Documents/Projects/sveltekit-todo-nodegui/nodetest1/svelte-nodegui-starter/node_modules
            single file module
              using description file: /Users/def/Documents/Projects/sveltekit-todo-nodegui/nodetest1/svelte-nodegui-starter/package.json (relative path: ./node_modules/@nodegui/svelte-nodegui)
                no extension```
  • 15

    Widget bindings should be generated - Lots of widgets are missing

    Svelte NodeGUI sounds just what I need for my application.

    The docs list only a number of very basic widgets. These seem to be implemented in React NodeGUI, and Svelte NodeGUI just bridges over the React implementations.

    For my real world application, I need a much larger number of Qt widgets. Without more widgets, I cannot even make a feasability study whether Svelte NodeGUI is suitable for my application, because the current set of widgets is just too small to find out whether it would work. Theoretically, I could add the widgets myself, but there are too many missing.

    However, I am faced with 5 layers of abstraction:

    1. OS widgets ->
    2. Qt ->
    3. Node GUI ->
    4. React NodeGUI ->
    5. Svelte NodeGUI

    This makes it difficult to add new widgets, because I need to understand a lot of intermediate wiring code, to add a widget. Worse, the mappings seem to be hand-written.

    May I suggest a different approach? Why don't you take the Qt widget API descriptions in computer-readable form, and then use Swig or a custom-made software to generate the bindings, for NodeGUI and each of React/Vue/Svelte NodeGUI?

    This would have the following advantages:

    • All Qt widgets supported, in all variants of NodeGUI
    • API up to date with new Qt versions
    • SvelteGUI would no longer need to use React NodeGUI, eliminating at least one level of indirection. (compare #21)
  • 16

    chrome://inspect not working as described in hello app

    The instructions mention click on "Source -> Node -> 'Your node process'" There is no "Source" thing to click, while there is sources? Also after clicking sources and node tab, there is no node process to look at.

    Unable to debug app when following the docs. Target is not listed.