Skip to content

Native app development framework for mobile and desktop using Go and HTMX.

Notifications You must be signed in to change notification settings

stukennedy/irgo

Repository files navigation

Irgo

A hypermedia-driven application framework that uses Go as a runtime kernel with Datastar. Build native iOS, Android, and desktop apps using Go, HTML, and Datastar - no JavaScript frameworks required.

Key Features

  • Go-Powered Apps: Write your backend logic in Go, compile to native mobile frameworks or desktop apps
  • Datastar for Interactivity: Use Datastar's hypermedia approach with SSE instead of complex JavaScript
  • Cross-Platform: Single codebase for iOS, Android, desktop (macOS, Windows, Linux), and web
  • Virtual HTTP (Mobile): No network sockets - requests are intercepted and handled directly by Go
  • Native Webview (Desktop): Real HTTP server with native webview window
  • Type-Safe Templates: Use templ for compile-time checked HTML templates
  • Hot Reload Development: Edit Go/templ code and see changes instantly

Architecture

Mobile Architecture (iOS/Android)

┌─────────────────────────────────────────────────────────────┐
│                      Mobile App                              │
│  ┌───────────────────────────────────────────────────────┐  │
│  │                 WebView (Datastar)                     │  │
│  │  • HTML rendered by Go templates                       │  │
│  │  • Datastar handles interactions via irgo:// scheme    │  │
│  └──────────────────────┬────────────────────────────────┘  │
│                         │                                    │
│  ┌──────────────────────▼────────────────────────────────┐  │
│  │           Native Bridge (Swift / Kotlin)               │  │
│  │  • Intercepts irgo:// requests                          │  │
│  │  • Routes to Go via gomobile                           │  │
│  └──────────────────────┬────────────────────────────────┘  │
│                         │                                    │
│  ┌──────────────────────▼────────────────────────────────┐  │
│  │              Go Runtime (gomobile bind)                │  │
│  │  • HTTP router (chi-based)                             │  │
│  │  • Template rendering (templ)                          │  │
│  │  • Business logic                                      │  │
│  └───────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

Desktop Architecture (macOS/Windows/Linux)

┌─────────────────────────────────────────────────────────────┐
│                     Desktop App                              │
│  ┌───────────────────────────────────────────────────────┐  │
│  │            Native Webview Window                       │  │
│  │  (System webview engine - Chromium/WebKit)            │  │
│  │  Navigates to: http://localhost:PORT                   │  │
│  └──────────────────────┬────────────────────────────────┘  │
│                         │                                    │
│  ┌──────────────────────▼────────────────────────────────┐  │
│  │         Go HTTP Server (localhost:PORT)                │  │
│  │  • Page Routes (Templ → HTML)                          │  │
│  │  • API Routes (SSE responses)                          │  │
│  │  • Static Asset Server (/static/*)                     │  │
│  └───────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

Quick Start

Prerequisites

  • Go 1.21+
  • templ: go install github.com/a-h/templ/cmd/templ@latest
  • air: go install github.com/air-verse/air@latest

For mobile development:

  • gomobile: go install golang.org/x/mobile/cmd/gomobile@latest && gomobile init
  • entr: brew install entr (macOS)
  • For iOS: Xcode with iOS Simulator
  • For Android: Android Studio with SDK and emulator

For desktop development:

  • CGO enabled (C compiler required)
  • macOS: Xcode Command Line Tools (included with Xcode)
  • Windows: MinGW-w64 or similar C compiler
  • Linux: GCC and WebKit2GTK dev packages (apt install libwebkit2gtk-4.0-dev)

Install Irgo CLI

go install github.com/stukennedy/irgo/cmd/irgo@latest

Or build from source:

git clone https://github.com/stukennedy/irgo.git
cd irgo/cmd/irgo
go install .

Create a New Project

irgo new myapp
cd myapp
go mod tidy
bun install  # or: npm install

Run as Desktop App

irgo run desktop         # Run as desktop app
irgo run desktop --dev   # With devtools enabled

Development with Hot Reload (Web)

irgo dev                 # Start dev server at http://localhost:8080

iOS Development

irgo run ios --dev       # Hot-reload with iOS Simulator
irgo run ios             # Production build

Build for Production

# Desktop
irgo build desktop           # Build for current platform
irgo build desktop macos     # Build macOS .app bundle
irgo build desktop windows   # Build Windows .exe
irgo build desktop linux     # Build Linux binary

# Mobile
irgo build ios               # Build iOS framework
irgo build android           # Build Android AAR

Project Structure

myapp/
├── main.go              # Mobile/web entry point (build tag: !desktop)
├── main_desktop.go      # Desktop entry point (build tag: desktop)
├── go.mod               # Go module definition
├── .air.toml            # Air hot reload configuration
├── package.json         # Node dependencies (Tailwind CSS)
│
├── app/
│   └── app.go           # Router setup and app configuration
│
├── handlers/
│   └── handlers.go      # HTTP handlers (business logic)
│
├── templates/
│   ├── layout.templ     # Base HTML layout
│   ├── pages.templ      # Page templates
│   └── components.templ # Reusable components
│
├── static/
│   ├── css/
│   │   ├── input.css    # Tailwind source
│   │   └── output.css   # Generated CSS
│   └── js/
│       └── datastar.js  # Datastar library
│
├── mobile/
│   └── mobile.go        # Mobile bridge setup
│
├── ios/                 # iOS Xcode project
├── android/             # Android project
│
└── build/
    ├── ios/             # Built iOS framework
    ├── android/         # Built Android AAR
    └── desktop/         # Built desktop apps
        ├── macos/       # macOS .app bundle
        ├── windows/     # Windows .exe
        └── linux/       # Linux binary

Desktop Development

How Desktop Mode Works

Desktop mode uses a different architecture than mobile:

  1. Real HTTP Server: A Go HTTP server starts on an auto-selected localhost port
  2. Native Webview: A native window with an embedded browser engine opens
  3. Standard HTTP: The webview navigates to the localhost URL - standard HTTP requests

This means your app works identically to the web dev server, but packaged as a native desktop app.

Desktop Entry Point

Projects include a main_desktop.go with build tag //go:build desktop:

//go:build desktop

package main

import (
    "flag"
    "fmt"
    "net/http"

    "myapp/app"
    "github.com/stukennedy/irgo/desktop"
)

func main() {
    devMode := flag.Bool("dev", false, "Enable devtools")
    flag.Parse()

    r := app.NewRouter()

    mux := http.NewServeMux()
    staticDir := desktop.FindStaticDir()
    mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(staticDir))))
    mux.Handle("/", r.Handler())

    config := desktop.DefaultConfig()
    config.Title = "My App"
    config.Debug = *devMode

    desktopApp := desktop.New(mux, config)

    fmt.Println("Starting desktop app...")
    if err := desktopApp.Run(); err != nil {
        fmt.Printf("Error: %v\n", err)
    }
}

Desktop Configuration

config := desktop.Config{
    Title:     "My App",      // Window title
    Width:     1024,          // Window width
    Height:    768,           // Window height
    Resizable: true,          // Allow window resize
    Debug:     false,         // Enable browser devtools
    Port:      0,             // 0 = auto-select available port
}

Running Desktop Apps

# Run directly (compiles and runs)
irgo run desktop

# With devtools (for debugging)
irgo run desktop --dev

Building Desktop Apps

# Build for current platform
irgo build desktop

# Build for specific platform
irgo build desktop macos     # Creates build/desktop/macos/MyApp.app
irgo build desktop windows   # Creates build/desktop/windows/MyApp.exe
irgo build desktop linux     # Creates build/desktop/linux/MyApp

Desktop vs Mobile: Key Differences

Aspect Mobile Desktop
HTTP Virtual (no sockets) Real localhost server
Bridge gomobile + native code None (direct HTTP)
Entry point main.go main_desktop.go
Build tag !desktop desktop
CGO Not required Required (webview)

Writing Handlers

Irgo supports two types of handlers:

Standard Handlers (Full Page Loads)

Return (string, error) with HTML:

r.GET("/about", func(ctx *router.Context) (string, error) {
    return renderer.Render(templates.AboutPage())
})

Datastar SSE Handlers

Return error and use ctx.SSE() for responses:

r.DSPost("/todos", func(ctx *router.Context) error {
    var signals struct {
        Title string `json:"title"`
    }
    ctx.ReadSignals(&signals)

    todo := createTodo(signals.Title)

    sse := ctx.SSE()
    sse.PatchTempl(templates.TodoItem(todo))
    sse.PatchSignals(map[string]any{"title": ""}) // Clear input
    return nil
})

Writing Templates

Templates use templ with Datastar attributes:

// templates/pages.templ
package templates

templ HomePage() {
    @Layout("Home") {
        <main class="container mx-auto p-4">
            <h1 class="text-2xl font-bold">Welcome to Irgo</h1>

            <div data-signals="{name: ''}">
                <input
                    type="text"
                    data-bind:name
                    placeholder="Your name"
                    class="border p-2 rounded"
                />
                <button
                    data-on:click="@post('/greeting')"
                    class="bg-blue-500 text-white px-4 py-2 rounded"
                >
                    Greet
                </button>
                <div id="greeting"></div>
            </div>
        </main>
    }
}

templ TodoItem(todo Todo) {
    <div id={ "todo-" + todo.ID } class="flex items-center gap-2 p-2">
        <input
            type="checkbox"
            checked?={ todo.Done }
            data-on:click={ fmt.Sprintf("@patch('/todos/%s')", todo.ID) }
        />
        <span>{ todo.Title }</span>
        <button
            data-on:click={ fmt.Sprintf("@delete('/todos/%s')", todo.ID) }
            class="text-red-500"
        >Delete</button>
    </div>
}

CLI Commands

# Create new project
irgo new myapp
irgo new .              # Initialize in current directory

# Development
irgo dev                # Start dev server with hot reload (web)
irgo run desktop        # Run as desktop app
irgo run desktop --dev  # Desktop with devtools
irgo run ios --dev      # Hot reload with iOS Simulator
irgo run android --dev  # Hot reload with Android Emulator

# Production builds
irgo build desktop      # Build desktop app for current platform
irgo build desktop macos/windows/linux  # Cross-platform builds
irgo build ios          # Build iOS framework
irgo build android      # Build Android AAR
irgo build all          # Build all mobile platforms

irgo run ios            # Build and run on iOS Simulator
irgo run android        # Build and run on Android Emulator

# Utilities
irgo templ              # Generate templ files
irgo install-tools      # Install required dev tools
irgo version            # Print version
irgo help [command]     # Show help

Datastar Overview

Datastar is a lightweight (~11KB) hypermedia framework that powers Irgo's interactivity:

  • SSE (Server-Sent Events): Server pushes HTML fragments to update the DOM
  • Reactive Signals: Client-side state with data-signals and $variable syntax
  • Declarative Actions: data-on:click="@get('/api')" triggers server requests

Key Datastar Attributes

Attribute Description Example
data-signals Initialize state data-signals="{count: 0}"
data-bind:X Two-way binding data-bind:name
data-on:event Event handler data-on:click="@post('/api')"
data-text Dynamic text data-text="$count"
data-show Conditional display data-show="$visible"

Troubleshooting

Desktop: "CGO_ENABLED=0" error

Desktop builds require CGO. Ensure you have a C compiler:

  • macOS: xcode-select --install
  • Windows: Install MinGW-w64
  • Linux: apt install build-essential

Desktop: Webview not showing

Check that WebKit2GTK is installed (Linux):

apt install libwebkit2gtk-4.0-dev

"Module not found" errors

go mod tidy

Hot reload not working

  1. Check if air is running
  2. Verify .air.toml configuration
  3. Make sure _templ.go is NOT in exclude_regex

Port 8080 already in use

lsof -i :8080
kill <PID>

License

MIT License - see LICENSE for details.

Acknowledgments

  • Datastar - The hypermedia framework that powers Irgo
  • templ - Type-safe HTML templating for Go
  • chi - Lightweight Go router
  • webview - Native webview for desktop
  • gomobile - Go on mobile platforms
  • air - Live reload for Go

About

Native app development framework for mobile and desktop using Go and HTMX.

Resources

Security policy

Stars

Watchers

Forks

Packages

No packages published