Your First Desktop App
In this course, you will install Wails, scaffold a desktop application with Grit, understand how Go functions are called directly from React, and run your app in dev mode. By the end, you will have a working desktop app with authentication, blog CRUD, and a SQLite database.
What is a Desktop App?
Desktop apps are different from web apps in several important ways:
- • They run locally — no browser needed, no internet required (unless your app needs it)
- • They can access the filesystem — read and write files on the user's computer
- • They feel faster — no network latency between the UI and backend
- • They are distributed as a single file — users download one executable and run it
Grit uses Wails to build desktop apps. You write Go for the backend and React for the UI — the same languages you already know from Grit web.
What is Wails?
Wails works by embedding a webview (a lightweight browser engine) inside a native window. Your React app runs in this webview, and Wails creates a bridge so JavaScript can call Go functions directly:
- • Go side: You write normal Go methods like
GetUsers()orCreateBlog(input) - • React side: You import and call them as if they were local functions —
const users = await GetUsers() - • No HTTP layer: No REST endpoints, no fetch(), no axios — direct function calls over an internal bridge
Learn more at wails.io. Wails supports Windows, macOS, and Linux from a single codebase.
Challenge: Visit Wails.io
Open wails.io in your browser. What platforms does Wails support? Find the "Getting Started" section — does it mention Go as a requirement?
Prerequisites
You need the same tools as Grit web (Go, Node.js, pnpm) plus one more — the Wails CLI:
| Tool | Version | Check |
|---|---|---|
| Go | 1.21+ | go version |
| Node.js | 18+ | node --version |
| pnpm | 8+ | pnpm --version |
| Wails CLI | v2 | wails version |
Install the Wails CLI with:
go install github.com/wailsapp/wails/v2/cmd/wails@latestAfter installation, verify everything is working:
wails doctorThe wails doctor command checks your system for all required dependencies (Go, Node, npm/pnpm, platform-specific build tools) and reports any issues.
Challenge: Install Wails CLI
Run go install github.com/wailsapp/wails/v2/cmd/wails@latest to install the Wails CLI. Then run wails doctor. Does it pass all checks? If any checks fail, follow the instructions to fix them.
Scaffold a Desktop App
The command for desktop apps is grit new-desktop — this is different from grit new which creates a web monorepo:
grit new-desktop myappgrit new-desktop creates a standalone app, not a monorepo. There is no apps/ folder, no packages/ folder, no Turborepo. Everything lives in a single flat directory. This is intentional — desktop apps are self-contained.After running the command, Grit creates a complete desktop project with authentication, blog CRUD, contact CRUD, a dark theme, and a SQLite database — all wired up and ready to run.
Challenge: Scaffold Your First Desktop App
Run grit new-desktop notes-app. Look at the folder structure that was created. How many Go files are in the root directory? How many folders are there?
Project Structure
A Grit desktop project has a flat, simple structure:
notes-app/
├── main.go <- Wails bootstrap + Go embed
├── app.go <- Bound methods (Go functions callable from React)
├── internal/ <- Go backend (models, services, config, db)
├── frontend/ <- React app (Vite + TanStack Router)
├── wails.json <- Wails configuration
└── .env <- Environment variablesCompare this to a Grit web project which has apps/api, apps/web, apps/admin, and packages/shared. A desktop project is much simpler — everything is in one place.
GetUsers() and call it from React as if it were a local function. No HTTP, no REST — direct function calls. Wails automatically generates TypeScript wrappers for every bound Go method.The key file is app.go — this is where all your Go methods that React can call are defined. Every public method on the App struct becomes available in the frontend:
type App struct {
ctx context.Context
authService *services.AuthService
blogService *services.BlogService
}
// React can call: Login({ email, password })
func (a *App) Login(input types.LoginInput) (*types.AuthResponse, error) {
return a.authService.Login(input)
}
// React can call: GetBlogs()
func (a *App) GetBlogs() ([]models.Blog, error) {
return a.blogService.List()
}Challenge: Explore app.go
Open app.go in your notes-app project. What methods are available? These are the functions React can call. Count how many public methods the App struct has.
Running in Dev Mode
Start your desktop app with either command:
cd notes-app
grit startOr use the Wails command directly:
wails devWhen you run grit start, a native desktop window opens with your app. The frontend dev server runs at localhost:34115 (you can also open it in a browser for debugging).
Challenge: Run Your Desktop App
Run grit start in your notes-app directory. The app should open as a desktop window. Try the login page — can you see the registration form?
SQLite Database
.db file in your project folder. No Docker, no PostgreSQL installation, no configuration. SQLite is the most widely deployed database engine in the world — it's inside every smartphone, every browser, and now inside your desktop app.Desktop apps use SQLite instead of PostgreSQL because users should not need to install a database server. The database file travels with the app — it's just a file on disk:
DB_PATH=./data.dbWhen the app starts, GORM automatically creates the .db file and runs migrations. You can browse the database with GORM Studio:
grit studioChallenge: Find the Database File
After running the app and registering an account, find the .db file in your project folder. Open GORM Studio with grit studio and browse the tables. Can you see the user you just registered?
Tour the App
Your scaffolded desktop app comes with everything you need to start building:
- • Login and Register pages — local authentication with bcrypt password hashing
- • Dashboard — stats cards showing total blogs, contacts, and recent activity
- • Blog CRUD — create, read, update, and delete blog posts
- • Contact CRUD — manage a contacts list with full CRUD operations
- • Sidebar navigation — collapsible sidebar with icons for every section
- • Dark theme — premium dark UI using Grit's design system
Challenge: Create Some Data
Register an account in your app. Create 3 blog posts with different titles and content. Create 2 contacts with names and emails. Visit the dashboard — do the stats update to show your new data?
The .env File
Desktop apps have a simpler .env file compared to web projects — no database URLs, no Redis, no S3 storage:
APP_NAME=notes-app
JWT_SECRET=your-secret-key-change-in-production
DB_PATH=./data.db
TOTP_ISSUER=notes-app- •
APP_NAME— your application name, shown in the title bar - •
JWT_SECRET— secret key for signing authentication tokens - •
DB_PATH— path to the SQLite database file - •
TOTP_ISSUER— name shown in authenticator apps for two-factor auth
Challenge: Read the .env File
Open the .env file in your project. What is the database file name? What is the JWT_SECRET set to?
Essential Commands
Here are the commands you'll use every day when building desktop apps:
| Command | What it does |
|---|---|
| grit start | Start the app in dev mode with hot reload |
| grit studio | Open the database browser for your SQLite database |
| grit generate resource | Generate a new CRUD resource (model, service, routes, UI) |
| grit routes | List all bound methods (desktop equivalent of API routes) |
| grit compile | Build a production-ready executable |
Challenge: Try the Commands
Run grit routes in your project folder. How many routes does the desktop app have? Can you identify which ones handle blogs and which handle contacts?
Challenge: Explore GORM Studio
Run grit studio. Browse the tables in your SQLite database. Can you see the blogs and contacts you created earlier? Try editing a record directly in Studio.
What You Learned
- What desktop apps are and how they differ from web apps
- What Wails is — Go + React desktop framework with direct function calls
- How to install the Wails CLI and verify with
wails doctor - How to scaffold a desktop app with
grit new-desktop - The flat project structure (main.go, app.go, internal/, frontend/)
- How Wails bindings work — Go methods callable from React
- How to run in dev mode with
grit startand hot reload - SQLite as the database — file-based, no server required
- The essential CLI commands for desktop development
Challenge: Final Challenge: Build a Todo App
Create a brand new desktop app called todo-app with grit new-desktop todo-app. Start it, register an account, create 5 blog posts, then open GORM Studio to see the data in SQLite. Verify the .db file exists in the project folder.
Challenge: Bonus: Compare Web vs Desktop
If you've completed the Grit Web course, create a web project with grit new webtest and a desktop project with grit new-desktop desktest side by side. List 3 differences you notice in the project structure, the way data is fetched, and the dev experience.
Enjoying the course?
Help us grow — star us on GitHub, subscribe on YouTube, and follow on LinkedIn.