Your First Desktop App
Build a Task Manager desktop application from scratch. This step-by-step tutorial covers scaffolding, development, resource generation, GORM Studio, and building for distribution.
What you'll build
A native desktop Task Manager with:
- • Full CRUD for tasks (title, description, priority, completion status, due date)
- • A categories resource to organize tasks
- • Search, pagination, PDF and Excel export
- • Authentication with login and default admin user
- • Visual database browsing with GORM Studio
- • A single native executable for distribution
Prerequisites
Make sure the following tools are installed on your system before starting:
go versionnode --versionwails versiongrit --helpInstall the Wails CLI:
Install the Grit CLI:
Run wails doctor to verify your environment. It checks for Go, Node.js, npm/pnpm, and platform-specific build tools (GCC on Linux, Xcode on macOS, or WebView2 on Windows).
Scaffold the Project
Create a new desktop project called taskmanager with the Grit CLI. This generates a complete Wails application with everything included.
Here is the project structure that gets created:
taskmanager/├── main.go # Wails entry point├── app.go # App struct with bound methods├── wails.json # Wails project configuration├── go.mod├── go.sum├── internal/│ ├── config/│ │ └── config.go # App configuration│ ├── db/│ │ └── db.go # GORM database setup (SQLite)│ ├── models/│ │ ├── user.go # User model + AutoMigrate│ │ ├── blog.go # Blog post model│ │ └── contact.go # Contact model│ ├── services/│ │ ├── auth.go # Authentication service│ │ ├── blog.go # Blog CRUD service│ │ └── contact.go # Contact CRUD service│ └── types/│ └── types.go # Shared request/response types├── frontend/│ ├── src/│ │ ├── main.tsx # React entry point (TanStack Router)│ │ ├── routes/ # File-based routes (TanStack Router)│ │ │ ├── __root.tsx # Root route│ │ │ ├── _layout.tsx # Auth guard + sidebar layout│ │ │ └── _layout/ # Protected page routes│ │ ├── components/ # Reusable UI components│ │ ├── hooks/ # TanStack Query hooks│ │ └── lib/ # Utilities│ ├── index.html│ ├── package.json│ ├── vite.config.ts│ └── tailwind.config.js└── cmd/└── studio/└── main.go # GORM Studio standalone server
What gets created out of the box:
Start Development
Navigate into the project and start Wails in development mode:
When you run wails dev, the following happens:
The frontend dev server also runs at http://localhost:34115, which you can open in a browser for debugging with browser DevTools.
On first run, wails dev installs frontend npm dependencies automatically. This takes a minute or two. Subsequent starts are much faster.Explore the Default App
Once the desktop window opens, log in with the default admin credentials:
admin@example.compasswordAfter logging in, explore what the scaffold gives you out of the box:
These built-in resources demonstrate every feature that your generated resources will also have: search, sorting, pagination, inline editing, bulk operations, and export.
Generate the Task Resource
Now for the main event. Open a new terminal in the taskmanager directory and run:
This single command creates 5 new files:
internal/models/task.goGORM model struct with all fields, timestamps, and soft delete
internal/services/task.goService with List, ListAll, GetByID, Create, Update, Delete methods
frontend/src/routes/_layout/tasks.index.tsxList route with search, pagination, edit/delete, PDF and Excel export
frontend/src/routes/_layout/tasks.new.tsxCreate form route with inputs mapped to each field type
frontend/src/routes/_layout/tasks.$id.edit.tsxEdit form route with pre-filled field values
It also injects code into 10 locations in existing files using grit: markers:
| File | Marker | What |
|---|---|---|
| db.go | // grit:models | Task model in AutoMigrate |
| main.go | // grit:service-init | TaskService initialization |
| main.go | /* grit:app-args */ | Service passed to NewApp |
| app.go | // grit:fields | TaskService field on App struct |
| app.go | /* grit:constructor-params */ | Constructor parameter |
| app.go | /* grit:constructor-assign */ | Field assignment |
| app.go | // grit:methods | 7 bound methods (CRUD + export) |
| types.go | // grit:input-types | TaskInput struct |
| cmd/studio/main.go | // grit:studio-models | Task model in Studio |
| sidebar.tsx | // grit:nav-icons + nav | Nav icon + sidebar item |
Here is the generated Go model:
type Task struct {ID uint `gorm:"primaryKey" json:"id"`Title string `json:"title"`Description string `json:"description"`Priority string `json:"priority"`Completed bool `json:"completed"`DueDate time.Time `json:"due_date"`CreatedAt time.Time `json:"created_at"`UpdatedAt time.Time `json:"updated_at"`DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"`}
Understanding the Generated Route Files
The three frontend files are TanStack Router route files. Each file exports a Route constant created with createFileRoute(). The TanStack Router Vite plugin auto-discovers these files — no import or route registry update is needed.
import { createFileRoute } from "@tanstack/react-router";// This line registers the route at /_layout/tasks/export const Route = createFileRoute("/_layout/tasks/")({component: TasksPage,});function TasksPage() {// DataTable with search, pagination, PDF/Excel export// Calls ListTasks() via Wails bindings}
The edit route uses Route.useParams() for type-safe parameter access. The $id in the filename becomes a typed parameter:
import { createFileRoute, useNavigate } from "@tanstack/react-router";export const Route = createFileRoute("/_layout/tasks/$id/edit")({component: EditTaskPage,});function EditTaskPage() {const { id } = Route.useParams(); // typed stringconst navigate = useNavigate();// Fetch task by ID, populate form// On save: navigate({ to: "/tasks" })}
Navigation uses TanStack Router's object syntax: navigate({ to: "/tasks" }) instead of navigate("/tasks"). All routes, params, and navigation calls are validated by TypeScript at compile time.
Test the Task Manager
Restart the development server to pick up the new Go code. If wails dev is still running, it automatically detects Go file changes and rebuilds. Otherwise, restart it:
Once the app reloads, you will see a new Tasks item in the sidebar. Click it to open the task list page. Try the following:
All of this was generated from a single CLI command. The list page, form, service methods, Wails bindings, routes, and sidebar navigation are all wired up automatically.
Generate Another Resource — Categories
To demonstrate how easy it is to add more resources, generate a Category resource for organizing tasks:
This creates 5 more files and injects into the same 10 locations. Your app now has:
| Resource | Source | Fields |
|---|---|---|
| Blog | Built-in (scaffold) | title, slug, content, image, published |
| Contact | Built-in (scaffold) | name, email, phone, message |
| Task | Generated (Step 5) | title, description, priority, completed, due_date |
| Category | Generated (Step 7) | name, color |
Each resource gets its own sidebar entry, list page, form page, Go model, and service. You can keep generating as many resources as your app needs.
Open GORM Studio
GORM Studio is a visual database browser bundled with every Grit desktop project. Open a separate terminal in the taskmanager directory and run:
Your browser opens automatically at http://localhost:8080/studio. You can:
Studio runs as a standalone Go process that connects to the same SQLite file your desktop app uses. This is useful for verifying data, debugging issues, and understanding the database schema during development.
Build for Distribution
When you are ready to ship, compile the app into a native executable:
This runs wails build under the hood. The output binary is placed in build/bin/:
| Platform | Output |
|---|---|
| Windows | build/bin/taskmanager.exe |
| macOS | build/bin/taskmanager.app |
| Linux | build/bin/taskmanager |
The resulting binary is a single executable with everything embedded:
For Windows, you can also create an NSIS installer with wails build -nsis. See the Building & Distribution guide for cross-platform builds and distribution details.What's Next
You have built a fully functional Task Manager desktop application with two custom resources, authentication, and database browsing — all from a few CLI commands. Here is where to go from here:
Resource Generation
Deep dive into field types, slug generation, belongs_to relationships, and the remove command.
Building & Distribution
Cross-platform builds, NSIS installers, app icons, environment config, and production tips.
Build a POS App
Follow the next tutorial to build a Point of Sale desktop application with products, orders, and receipts.
Desktop LLM Reference
The complete Grit desktop reference for AI assistants — every convention, pattern, and code marker.