Using Other Frontend Frameworks
Wails ships built-in starter templates for a deliberately small set of frameworks:
| Template | Language |
|---|---|
vanilla |
TypeScript (default) |
vanilla-js |
JavaScript |
react |
TypeScript |
react-js |
JavaScript |
vue |
TypeScript |
svelte |
TypeScript |
That doesn’t mean those are your only options. The frontend of a Wails app is just a web project — anything that builds to static HTML/CSS/JS will work. If your framework of choice (Solid, Preact, Lit, Qwik, SvelteKit, Angular, …) doesn’t have a template, you can scaffold it yourself in a couple of minutes.
How the frontend/ directory is used
Wails does not care which framework lives in frontend/. It only relies on a small,
framework-agnostic contract:
frontend/dist/is what ships.main.goembeds the built frontend with//go:embed all:frontend/distand serves it from the asset server. Your build must output a static bundle tofrontend/dist/(Vite’s default output directory).- The build is driven by
frontend/package.json. Duringwails3 build, Wails runs the frontend’sbuildscript; duringwails3 devit runsdevand proxies the Vite dev server for hot reload. - Bindings are generated into
frontend/bindings/. Wails inspects your registered Go services and writes a type-safe SDK there. You import from it like any other module:
import { GreetService } from "./bindings/changeme";- The dev server runs on a fixed port.
wails3 devproxies Vite on the port inWAILS_VITE_PORT(default9245), so setserver.portto it withstrictPort: true. This is ordinary Vite config — no Wails plugin is involved. - Optional — typed custom events. The built-in templates also register the
@wailsio/runtime/plugins/viteplugin. It’s only needed if you use typed custom events: it injects your generated event-type definitions into the runtime and makes the build fail until bindings have been generated. If you only use the string-basedEvents.On("time", …)API, you can leave it out.
Everything else — components, routing, state, styling — is entirely up to your framework.
Scaffold any framework with Vite
The fastest path is to start from a built-in template (so you get main.go, the
Taskfile, build assets and a working Go service), then replace frontend/ with a fresh
Vite project for your framework.
Create a project from the default template
wails3 init -n myapp
cd myapp
Replace `frontend/` with a Vite app for your framework
Vite can scaffold most frameworks with a single command. Pick a template:
# From the project root — e.g. Solid, Preact, Lit, Svelte, Vue, React, Vanilla
rm -rf frontend
npm create vite@latest frontend -- --template solid
Swap solid for any Vite template: preact, lit, svelte, vue, react,
vanilla, or their -ts variants (solid-ts, preact-ts, …).
Install the runtime and point Vite at the Wails dev server
cd frontend
npm install @wailsio/runtime
@wailsio/runtime provides the JS APIs (Events, Browser, dialogs, …). The only
required vite.config change is the dev-server port, so wails3 dev can find it:
import { defineConfig } from "vite";
export default defineConfig({
server: {
host: "127.0.0.1",
port: Number(process.env.WAILS_VITE_PORT) || 9245,
strictPort: true,
},
});Only if you intend to use typed custom events, also add the plugin — it injects your generated event types and requires bindings to exist before the build:
import { defineConfig } from "vite";
import wails from "@wailsio/runtime/plugins/vite";
export default defineConfig({
plugins: [wails("./bindings")],
server: { host: "127.0.0.1", port: Number(process.env.WAILS_VITE_PORT) || 9245, strictPort: true },
});Call your Go services
Generate bindings once, then import them anywhere in your components:
wails3 generate bindings
import { GreetService } from "./bindings/changeme";
const greeting = await GreetService.Greet("World");Run it
wails3 dev
Frameworks with their own scaffolder
A few frameworks aren’t created through Vite’s create templates and have their own
tooling. They still work — just scaffold them with their native command and add the
Wails plugin afterwards:
- SvelteKit:
npx sv create frontend. Use the static adapter (@sveltejs/adapter-static) so it builds to a static bundle, and disable SSR. - Qwik:
npm create qwik@latest. Use the static (SSG) adapter. - Angular: scaffold with
ng new, setoutputPathtodist, and point the build script atng build.
The rule is always the same: produce a static build in frontend/dist/, keep the
@wailsio/runtime Vite plugin (or import the runtime directly), and import your Go
bindings from frontend/bindings/.