Why donate
API Explorer
Upgrade Guide
Creating a New Project
The /quasar.config File
Convert q/app-webpack Project
Browser Compatibility
TypeScript Support
Directory Structure
Commands List
CSS Preprocessors
Page Routing with VueRouter
Lazy Loading - Code Splitting
Handling Assets
Boot Files
Prefetch Feature
API Proxying
Handling Vite
Handling import.meta.env
State Management with Pinia
Lint and Format Code
Testing & Auditing
Developing Mobile Apps
Fetching Data
Opening Dev Server To Public
Quasar CLI with Vite - @quasar/app-vite v3
Deploying a SPA

Many services can deploy a static SPA. This page focuses on the general requirements and gives examples for several common providers.

If your favorite deployment tool is missing feel free to create a pull request on GitHub to add it to the list.

General deployment

The first step is to build a production bundle:

To produce such a build use Quasar CLI with the following command:

quasar build

By default, this writes the production-ready files to /dist/spa. If you configure build.distDir, deploy that directory instead.

Serve these files through HTTP or HTTPS. Opening index.html directly with the file:// protocol is not supported.

Common choices for web servers are nginx, Caddy, Apache, Express; but you should be able to use whatever web server you want.

Hash-mode routing requires only static file hosting. History-mode routing also requires a fallback that serves index.html when a requested application route does not match a static file. Do not rewrite requests for existing assets.

An example config for nginx may look like this:

server {
    listen 80;
    server_name quasar.myapp.com;

    root /home/user/quasar.myapp.com/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";

    index index.html;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/quasar.myapp.com-error.log error;

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

Important Hosting Configuration

Do not cache index.html for long periods. Otherwise, returning visitors may continue loading asset URLs from an older deployment. Hashed JavaScript, CSS, and other immutable assets can be cached for much longer.

Configure a revalidation policy for index.html, such as Cache-Control: no-cache, through your hosting service.

As an example how this is done for Google Firebase, you would add the following to the firebase.json configuration:

firebase.json

{
  "hosting": {
    "headers": [
      {
        "source": "/index.html",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "no-cache"
          }
        ]
      },
      {
        "source": "**/*.@(jpg|jpeg|gif|png|svg|webp|js|css|eot|otf|ttf|ttc|woff|woff2|font.css)",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "public, max-age=31536000, immutable"
          }
        ]
      }
    ]
  }
}

Deploying with Cloudflare Pages

Cloudflare Pages can deploy the SPA directly from a Git repository. Configure the Pages project with:

  • Build command: quasar build
  • Build output directory: dist/spa

Cloudflare rebuilds the site when you push to the connected production or preview branches. When no top-level 404.html is deployed, Pages treats the project as a SPA and routes unknown paths to index.html.

For a direct upload instead, install Wrangler and deploy the built directory:


pnpm add -D wrangler
pnpm quasar build
pnpm wrangler pages deploy dist/spa

If you change build.distDir, pass the configured output directory instead. See the Cloudflare Pages documentation for Git integration, direct uploads, redirects, and custom domains.

Deploying with Vercel

Connect the Git repository to Vercel and configure:

  • Build command: quasar build
  • Output directory: dist/spa

For CLI deployment, install the Vercel CLI, log in, and run it from the project root:

vercel login
vercel

For history-mode routing, add vercel.json at the project root. The filesystem check lets static assets resolve before the SPA fallback:

vercel.json

{
  "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}

You can also define project scripts:

/package.json

"scripts": {
  "build": "quasar build",
  "deploy": "vercel --prod"
}

If you change build.distDir, update Vercel’s output directory to match.

Deploying with Heroku

Heroku does not serve static sites directly, so the application needs a small HTTP server.

In this example, we will use Express to create a minimal server which Heroku can use.

First, we need to install the required dependencies to our project:


pnpm add express serve-static connect-history-api-fallback

Now that we have installed the required dependencies, we can add our server. Create a file called server.js in the root directory of your project.

import path from 'node:path'
import express from 'express'
import serveStatic from 'serve-static'
import history from 'connect-history-api-fallback'

const port = process.env.PORT || 5000
const app = express()

app.use(history())
app.use(serveStatic(path.join(import.meta.dirname, 'dist/spa')))
app.listen(port)

Heroku expects a set of package scripts, so add the following under scripts in package.json:

/package.json

"scripts": {
  "build": "quasar build",
  "start": "node server.js",
  "heroku-postbuild": "quasar build"
}

Now it is time to create an app on Heroku by running:

heroku create

and deploy to Heroku using:

git init
heroku git:remote -a <heroku app name>

git add .
git commit -am "make it better"
git push heroku main

For existing Git repositories, simply add the heroku remote:

heroku git:remote -a <heroku app name>

Deploying with Surge

Surge is a popular tool to host and deploy static sites.

If you want to deploy your application with Surge you first need to install the Surge CLI tool:


pnpm add --global surge

Next, we will use Quasar CLI to build our app:

quasar build

Now we can deploy our application using Surge by calling:

surge dist/spa

Now your application should be successfully deployed using Surge. You should be able to adapt this guide to any other static site deployment tool.

Deploying on GitHub Pages

GitHub Pages can deploy the production bundle with GitHub Actions. In the repository settings, select Pages > Build and deployment > GitHub Actions, then add .github/workflows/deploy.yml:

name: Deploy Quasar SPA to GitHub Pages

on:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: pages
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: pnpm
      - run: pnpm install --frozen-lockfile
      - run: pnpm quasar build
      - uses: actions/upload-pages-artifact@v4
        with:
          path: dist/spa

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy
        id: deployment
        uses: actions/deploy-pages@v4

For a project site served from https://<username>.github.io/<repository>/, set build.publicPath to /<repository>/. A user or organization site named <username>.github.io is served from / and does not need that override.

GitHub Pages does not provide a general history-mode fallback to index.html. Use Vue Router’s hash mode unless every route has a corresponding static file or another layer handles the rewrites.

To use a custom domain, configure it in the repository’s Pages settings. See the GitHub Pages documentation for DNS and domain-verification instructions.