Build Once, Deploy Everywhere: How Quasar’s CLI‑Driven Targets Let You Ship SPA, PWA, SSR, and Native Apps from a Single Codebase
Quasar’s CLI lets you build SPA, PWA, SSR, and native apps from one codebase. Learn how to add modes, switch rendering strategies, and verify artifacts—all while understanding the trade‑offs.
22 Jul 2025, 11:17 UTC

Problem: Fragmented Codebases for Every Platform
When building a modern app, developers often end up with separate codebases for the web, progressive web app (PWA), server‑side rendered (SSR) version, and mobile apps (Cordova/Capacitor). Each target requires its own build scripts, configuration files, and sometimes even duplicated UI logic. The result is higher maintenance cost and a higher chance of feature drift.
Thesis: Quasar’s CLI‑Driven Build Targets Solve It
Quasar Framework abstracts platform differences behind a single, declarative CLI. By adding a mode—spa, pwa, ssr, cordova, capacitor, or bems—you can generate the exact build artifacts you need without touching your Vue components. The trade‑off is that each mode adds its own build time and may expose platform‑specific quirks.
Section 1: Adding Modes with the Quasar CLI
Start with a fresh project:
npx @quasar/cli create my-app
cd my-app
quasar dev
To enable PWA support, run:
quasar mode add pwa
The CLI will install @quasar/app-pwa and configure quasar.conf.js. You can add multiple modes; Quasar will keep the configuration in a single file, but each mode will generate its own dist folder.
Section 2: Switching Between SPA and SSR
Quasar lets you switch rendering strategies with a single command:
quasar dev -m spa # SPA, client‑side only
quasar dev -m ssr # SSR, server‑side rendering
SSR introduces a Node.js server that renders the initial page. Because the same Vue components run on both client and server, you must guard any browser‑only APIs:
if (process.client) {
// window, document, localStorage
}
During SSR, the window object is undefined, so checks like process.client prevent runtime errors.
Section 3: Mobile Builds with Capacitor
To target native mobile platforms, add Capacitor:
quasar mode add capacitor
Capacitor bundles your Vue code into an Android or iOS project. The same src directory is reused, and Quasar’s UI components automatically adapt to touch gestures. If you need native hardware access, install a Capacitor plugin and import it where needed:
npm i @capacitor/geolocation
import { Geolocation } from '@capacitor/geolocation';
async function getLocation() {
const position = await Geolocation.getCurrentPosition();
console.log(position);
}
Remember that a plugin may not be available for all platforms; test each target separately.
Section 4: Build Artifacts and Verification
Run a full build for each mode:
quasar build -m spa
quasar build -m ssr
quasar build -m capacitor
Check the dist/spa, dist/ssr, and dist/capacitor folders. In dist/ssr, you’ll see a server.js file that starts the Node server. In dist/capacitor, you’ll find platform‑specific directories for Android and iOS.
Trade‑Offs and Limitations
- Build Time: Adding more modes increases total build time, especially when generating native projects.
- Platform Quirks: Some features (e.g., push notifications) require platform‑specific code paths.
- SSR Complexity: Server‑side code cannot access browser globals; you must guard against it.
Actionable Closing
By leveraging Quasar’s mode system, you can keep a single repository and deliver to web, PWA, SSR, and mobile platforms with minimal friction. Start by adding the modes you need, then use quasar dev -m <mode> to iterate quickly. Always run a full quasar build for each target before shipping to catch platform‑specific build errors early.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.