Building a Vue 3 Desktop App With Pinia, Electron and Quasar (2024)

Recently, I planned to rewrite my "Scrum Daily Standup Picker" Electron application in Vue 3. I wrote the initial release in Angular, but I wanted to refactor the code base and rewrite it in Vue 3.

Why? Because I love Vue and want to have a public showcase that I can reference to potential customers.

Quasar is an MIT licensed open-source Vue.js based framework that targets SPA, SSR, PWA, mobile app, desktop app, and browser extension all using one codebase.It handles the build setup and provides a complete collection of Material Design compliant UI components.

Quasar's motto is:

Write code once and simultaneously deploy it as a website, a Mobile App and/or an Electron App.

Using Quasar drastically saves development time due to these reasons:

  • It's based on Vue.js.
  • It provides many UI components that follow Material Design guidelines.
  • It has a regular release cycle inclusive of new features.
  • It provides support for each build mode (SPA, SSR, PWA, Mobile app, Desktop app & Browser Extension).
  • It has its own CLI that provides a pleasant developer experience. For example, we can build our application as SPA, mobile, or desktop app within the same project folder.

Read more about why Quasar might be a good choice for your next project.

Install Quasar CLI


The source code for the following demo is available at GitHub


1# Node.js >=12.22.1 is required.23$ yarn global add @quasar/cli4# or5$ npm install -g @quasar/cli

Let's start by creating a new project using the Quasar CLI:


1 quasar create vue3-electron-demo23 ___4 / _ \ _ _ __ _ ___ __ _ _ __5| | | | | | |/ _` / __|/ _` | '__|6| |_| | |_| | (_| \__ \ (_| | |7 \__\_\\__,_|\__,_|___/\__,_|_|891011? Project name (internal usage for dev) vue3-electron-demo12? Project product name (must start with letter if building mobile apps) Quasar App13? Project description A Quasar Framework app14? Author Michael Hoffmann <>15? Pick your CSS preprocessor: SCSS16? Check the features needed for your project: ESLint (recommended), TypeScript17? Pick a component style: Composition18? Pick an ESLint preset: Prettier19? Continue to install project dependencies after the project has been created? (recommended) NPM

We chose SCSS as our CSS preprocessor, ESLint & Typescript as additional features, Vue 3's Composition API and Prettier for code formatting.


Do not choose Vuex as we will add another state library in the next chapter. If you accidentally added Vuex, remove it manually from your package.json.

Read the official docs for additional information about the Quasar CLI.

We'll use Pinia as Vue store library, which is now the recommended state library for Vue.

First, we need to install Pinia:

To be able to register Pinia at our Vue application instance we need to create a Quasar Boot File:

A common use case for Quasar applications is to run code before the root Vue app instance is instantiated, like injecting and initializing your own dependencies (examples: Vue components, libraries…) or simply configuring some startup code of your app.

Our boot file is called pinia.ts and is located at src/boot:

1import { boot } from 'quasar/wrappers'2import { createPinia } from 'pinia'34export default boot(({ app }) => {5 app.use(createPinia())6})

We also need to add this new file to quasar.conf.js:

1module.exports = configure(function (ctx) {2 return {3 ...4 // app boot file (/src/boot)5 // --> boot files are part of "main.js"6 // boot: ['pinia'],8 ...9 }10}

Now, we can create a new folder called pinia in src.


We cannot name this folder store as this name is reserved for the official Vuex integration.

A basic store could look like this:

1import { defineStore } from 'pinia'23// useStore could be anything like useUser, useCart4// the first argument is a unique id of the store across your application5const useStore = defineStore('storeId', {6 state: () => {7 return {8 counter: 0,9 lastName: 'Michael',10 firstName: 'Michael',11 }12 },13 getters: {14 fullName: (state) => `${state.firstName} ${state.lastName}`,15 },16 actions: {17 increment() {18 this.counter++19 },20 },21})2223export default useStore

We can use this store in any Vue component:

1<template>Counter: {{ store.counter }}</template>23<script setup lang="ts">4import { useStore } from '@/stores/counter'56const store = useStore()7</script>

Now we can run the Vue application using the Quasar CLI:


quasar dev

The Vue application is served at http://localhost:8080:

Building a Vue 3 Desktop App With Pinia, Electron and Quasar (1)

Setup Electron


Read this introduction if you are new to Electron.

To develop/build a Quasar Electron app, we need to add the Electron mode to our Quasar project:


quasar mode add electron

Every Electron app has two threads: the main thread (deals with the window and initialization code – from the newly created folder /src-electron) and the renderer thread (which deals with the actual content of your app from /src).

The new folder has the following structure:

1.2└── src-electron/3├── icons/ # Icons of your app for all platforms4| ├── icon.icns # Icon file for Darwin (MacOS) platform5| ├── icon.ico # Icon file for win32 (Windows) platform6| └── icon.png # Tray icon file for all platforms7├── electron-preload.js # (or .ts) Electron preload script (injects Node.js stuff into renderer thread)8└── electron-main.js # (or .ts) Main thread code

Now we are ready to start our Electron application:


quasar dev -m electron

This command will open up an Electron window which will render your app along with Developer Tools opened side by side:

Building a Vue 3 Desktop App With Pinia, Electron and Quasar (2)

Read the official docs for additional and detailed information about developing Electron apps with Quasar.

If we want to use Electron features like opening a file dialog, we need to write some code to be able to access Electron's API.

For example, if we want to show a dialog to open files, Electron provides the dialog API to display native system dialogs for opening and saving files, alerting, etc.

First, we need to install @electron/remote:


npm install -D @electron/remote

Then we need to modify src-electron/electron-main.js and initialize @electron/remote:

1import { app, BrowserWindow, nativeTheme } from 'electron'2import { initialize, enable } from '@electron/remote/main'3import path from 'path'4import os from 'os'56initialize()78let mainWindow910function createWindow() {11 /**12 * Initial window options13 */14 mainWindow = new BrowserWindow({15 icon: path.resolve(__dirname, 'icons/icon.png'), // tray icon16 width: 1000,17 height: 600,18 useContentSize: true,19 webPreferences: {20 contextIsolation: true,21 // More info: /quasar-cli/developing-electron-apps/electron-preload-script22 preload: path.resolve(__dirname, process.env.QUASAR_ELECTRON_PRELOAD),23 },24 })2526 // ....2728 enable(mainWindow.webContents)29}

If we want to use Electron API from our Vue code we need to add some code to src-electron/electron-preload.js:

1import { contextBridge } from 'electron'2import { dialog } from '@electron/remote'34// 'electronApi' will be available on the global window context5contextBridge.exposeInMainWorld('electronApi', {6 openFileDialog: async (title, folder, filters) => {7 // calling showOpenDialog from Electron API: const response = await dialog.showOpenDialog({9 title,10 filters,11 properties: ['openFile', 'multiSelections'],12 })13 return response.filePaths14 },15})

Next we create src/api/electron-api.ts to access this code from within our Vue application:

1export interface ElectronFileFilter {2 name: string3 extensions: string[]4}56export interface ElectronApi {7 openFileDialog: (title: string, folder: string, filters: ElectronFileFilter) => Promise<string[]>8}910// eslint-disable-next-line @typescript-eslint/ban-ts-comment11// @ts-ignore12export const electronApi: ElectronApi = (window as { electronApi: ElectronApi }).electronApi

Now we can use this API anywhere in our Vue component:

1<template>2 <q-btn @click="openElectronFileDialog">Open Electron File Dialog</q-btn>3</template>45<script lang="ts">6import { defineComponent } from 'vue'7import { electronApi } from 'src/api/electron-api'89export default defineComponent({10 name: 'PageIndex',11 components: {},12 setup() {13 const openElectronFileDialog = async () => {14 return electronApi.openFileDialog('Test', 'folder', { name: 'images', extensions: ['jpg'] })15 }1617 return { openElectronFileDialog }18 },19})20</script>

Clicking on the button should now open the native OS file dialog:

Building a Vue 3 Desktop App With Pinia, Electron and Quasar (3)


Quasar allows us to quickly develop Electron desktop applications in Vue with high-quality UI components that follow Material Design guidelines.

The most significant advantage against a custom Electron + Vue boilerplate project from GitHub is that Quasar has a regular release cycle and provides upgrade guides for older versions.

Take a look at my "Scrum Daily Standup Picker" GitHub repository to see a more complex "Quasar-Electron-Vue3-Typescript-Pinia" project. The demo source code for the following demo is available at GitHub.

If you liked this article, follow me on Twitter to get notified about new blog posts and more content from me.

Alternatively (or additionally), you can also subscribe to my newsletter.

Building a Vue 3 Desktop App With Pinia, Electron and Quasar (2024)


Is Quasar compatible with Vue 3? ›

Quasar UI v2 is based on Vue 3, as opposed to the previous version which was based on Vue 2. This means that your app code (Vue components, directives, etc) should be Vue 3 compliant too, not just the Quasar UI source-code.

Do I need to learn Vue before quasar? ›

If you are new to Quasar and a… (Beginner Vue) JavaScript Dev - We highly recommend learning Vue. Intermediate Vue Dev - We recommend getting accustomed to Quasar's Directory Structure and its different build modes, starting with SSR (the project you built is an SPA).

Can I use Vue with Electron? ›

electron-vue takes advantage of vue-cli for scaffolding, webpack with vue-loader , electron-packager or electron-builder , and some of the most used plugins like vue-router , vuex , and so much more.

How to use quasar in vue? ›

Using Quasar Components

In order to use them, you need to add a reference to them in the /quasar. config file. Notice how QBtn is used in the Vue HTML template as <q-btn> . If we'd import QElementResizeObserver, then we'd use it in template as <q-element-resize-observer> .

Is Quasar better than vuetify? ›

Which one to choose? Quasar is the go-to choice for projects where you need to target multiple platforms from the same codebase. Vuetify and PrimeVue are better suited for web-centric projects. If you're specifically looking for Material Design, Vuetify or Quasar would be preferable.

Is there a big difference between Vue 2 and Vue 3? ›

In general, Vue 3 provides smaller bundle sizes, better performance, better scalability, and better TypeScript / IDE support. If you are starting a new project today, Vue 3 is the recommended choice. There are only a few reasons for you to consider Vue 2 as of now: You need to support IE11.

How many days it will take to learn Vue? ›

If you are already familiar with JavaScript and web development concepts, it may take you a few weeks to become proficient with Vue. js. However, if you are new to web development, it may take you several months to learn Vue.

Is Vue good for small projects? ›

Vue can be considered a very light-weight frontend framework options. It was designed to be “incrementally adoptable” - you can start using it without much overhead in any of your Django templates.

What is the best testing library for Vue? ›

Useful Libraries for Testing
  • Vue Testing Library. Vue Testing Library is a set of tools focused on testing components without relying on implementation details. ...
  • vuex-mock-store. ...
  • jest-matcher-vue-test-utils. ...
  • jest-mock-axios.

Should I use Electron for desktop app? ›

Electron is an excellent option for businesses that need to build desktop applications with a native look and feel. Electron provides access to native operating system APIs, allowing developers to build high-performance desktop applications with the same technologies they use for web development.

What are the disadvantages of Electron app? ›

Memory Consumption

Electron apps may use more memory compared to native applications, potentially affecting the performance of systems with limited resources. Developers need to implement strategies to optimize memory usage and ensure a smoother user experience.

Is tauri better than electrons? ›

Security: Tauri is more secure than Electron by default. This is because Tauri uses Rust, a memory-safe language, to build its web renderer. Electron, on the other hand, uses JavaScript, which is not memory-safe. This means that Tauri apps are less likely to be vulnerable to memory corruption attacks.

How do I add Pinia to Quasar? ›

Adding a Pinia store is easy with Quasar CLI through the $ quasar new command. It will create a folder in /src/stores named by “store_name” from the command above. It will contain all the boilerplate that you need. More info on defining a Pinia store .

Is the Quasar framework free? ›

Quasar is and always will be 100% free and open-source under the MIT license. Fork it on GitHub and help make it bettter.

What is the difference between element plus and Quasar? ›

Element Plus is designed specifically for Vue. js and offers seamless integration with Vue projects. It provides an intuitive API and follows the Vue component ecosystem conventions. Quasar, on the other hand, is a full-fledged framework that can be used for building complete Vue applications.

How to install Vite Vue 3? ›

How to Get Started?
  1. First, install Vue 3 using the following terminal command: npm install vue@next.
  2. Next, install Vite using the following command: npm init vite@latest my-app. ...
  3. After creating your project, navigate to the generated directory and run the following command to install the necessary dependencies: npm install.
Nov 28, 2023

Can I use Quasar with Tailwind? ›

Now in your Quasar project you can use any of the tailwind classes, prefixed with `tw-` to make sure they don't clash with any of Quasar's classes. Note that when you use a modifier class, you must use the `tw-` after the modifier. e.g. `hover:tw-underline`.

What is the equivalent of a Quasar react? ›

Vuetify, Ionic, Nuxt. js, React Native, and Flutter are the most popular alternatives and competitors to Quasar Framework. Powerful collaboration, review, and code management for open ... Powerful collaboration, review, and code management for open ...

Top Articles
Latest Posts
Article information

Author: Manual Maggio

Last Updated:

Views: 5483

Rating: 4.9 / 5 (49 voted)

Reviews: 80% of readers found this page helpful

Author information

Name: Manual Maggio

Birthday: 1998-01-20

Address: 359 Kelvin Stream, Lake Eldonview, MT 33517-1242

Phone: +577037762465

Job: Product Hospitality Supervisor

Hobby: Gardening, Web surfing, Video gaming, Amateur radio, Flag Football, Reading, Table tennis

Introduction: My name is Manual Maggio, I am a thankful, tender, adventurous, delightful, fantastic, proud, graceful person who loves writing and wants to share my knowledge and understanding with you.