Now with Desktop Support

Native Apps with
Go + Datastar

Build native iOS, Android, and desktop apps using Go, HTML, and Datastar. The richness of a webapp in a native app. No JavaScript frameworks required.

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

One Codebase. Every Platform.

Write your app logic once in Go. Deploy everywhere.

iOS

Native iOS apps via gomobile

Android

Native Android apps via gomobile

Desktop

macOS, Windows, Linux with webview

Web

Standard HTTP server for browsers

Why irgo?

The hypermedia approach to native app development

Go-Powered Runtime

Write your backend logic in Go. Compile to native mobile frameworks or desktop apps with full access to the Go ecosystem.

Datastar for Interactivity

Use Datastar's hypermedia approach with SSE instead of complex JavaScript frameworks. Return HTML via Server-Sent Events. Simple and powerful.

Type-Safe Templates

Use templ for compile-time checked HTML templates. Catch errors at build time, not runtime. Full Go type safety.

Virtual HTTP (Mobile)

No network sockets on mobile. Requests are intercepted and handled directly by Go in-process. Fast and secure.

Hot Reload Development

Edit Go and templ code and see changes instantly. Full hot reload support for rapid development.

Powerful CLI

Create, develop, and build projects with simple commands. irgo new, irgo dev, irgo build - that's it.

Simple, Expressive Code

Build interactive UIs with Go handlers and templ templates

Handler

handlers/todos.go
func CreateTodo(ctx *router.Context) error {    var signals struct {        Title string `json:"title"`    }    ctx.ReadSignals(&signals)    if signals.Title == "" {        return ctx.SSE().PatchTempl(            templates.Error("Title required"))    }    todo := db.CreateTodo(signals.Title)    sse := ctx.SSE()    sse.PatchTempl(templates.TodoItem(todo))    sse.PatchSignals(map[string]any{"title": ""})    return nil}

Template

templates/todos.templ
templ TodoItem(todo Todo) {    <div id={ "todo-" + todo.ID } class="todo-item">        <input            type="checkbox"            checked?={ todo.Done }            data-on:click={ "@patch('/todos/" + todo.ID + "')" }        />        <span class={ templ.KV("done", todo.Done) }>            { todo.Title }        </span>        <button            data-on:click={ "@delete('/todos/" + todo.ID + "')" }        >x</button>    </div>}

The Thin Client Advantage

Go compiles your app and serves HTML partials directly. No frontend framework, no JSON APIs, no virtual DOM.

Go RuntimeHandlers + TemplatesHTML Partials<div>Hello</div><button/><li>Item</li>No JS FrameworkWebViewRenderSwapThin Client: Server renders HTML, client just displays itDatastarirgo: Go renders → HTML partials → DOM updateTraditional: API → JSON → JS Framework → Virtual DOM → DOM

Mobile Architecture

WebViewHTML + Datastarirgo://Native BridgeSwift / KotlinIn-processGo Runtimegomobile bindNo network socketsVirtual HTTP in-processiOS / Android

How It's Different

Traditional SPA

API → JSON → JS Framework → Virtual DOM → DOM reconciliation

React/Vue/AngularState ManagementBuild Tools

irgo Approach

Go Handler → templ → SSE → DOM morph

No JS FrameworkServer StateJust Go

The client is thin. It just renders what Go sends. Datastar handles the SSE updates and DOM morphing. Your Go code is the single source of truth.

Platform Comparison

Choose the right mode for your target platform

AspectMobile (iOS/Android)DesktopWeb
HTTPVirtual (no sockets)Real localhost serverReal HTTP server
Bridgegomobile + native codeNone (direct HTTP)None
Entry Pointmain.gomain_desktop.gomain.go (serve)
Build Tag!desktopdesktop!desktop
CGO RequiredNoYes (webview)No

Ready to Build?

Get started in minutes. Create your first irgo app and deploy to any platform.