Project Structure
An irgo project follows a clean, conventional structure that separates concerns while keeping related code together.
Directory Layout
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 4)│├── app/│ └── app.go # Router setup and app configuration│├── handlers/│ └── handlers.go # HTTP handlers (business logic)│├── templates/│ ├── layout.templ # Base HTML layout│ ├── home.templ # Home page template│ └── components.templ # Reusable components│├── static/│ ├── css/│ │ ├── input.css # Tailwind source│ │ └── output.css # Generated CSS│ └── js/│ ├── htmx.min.js # HTMX library (downloaded automatically)│ └── hx-ws.js # HTMX WebSocket extension│├── 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 binaryEntry Points
irgo uses Go build tags to separate platform-specific entry points:
Mobile/Web Entry Point
//go:build !desktoppackage mainimport ( "fmt" "log" "net/http" "os" "myapp/app" "github.com/stukennedy/irgo/mobile")func main() { // If run with "serve" argument, start web dev server if len(os.Args) > 1 && os.Args[1] == "serve" { runDevServer() return } // Otherwise, initialize for mobile initMobile()}func initMobile() { mobile.Initialize() r := app.NewRouter() mobile.SetHandler(r.Handler()) fmt.Println("Mobile app initialized")}func runDevServer() { r := app.NewRouter() mux := http.NewServeMux() mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) mux.Handle("/", r.Handler()) fmt.Println("Dev server at http://localhost:8080") log.Fatal(http.ListenAndServe(":8080", mux))}Desktop Entry Point
//go:build desktoppackage mainimport ( "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) }}The //go:build !desktop and //go:build desktop tags ensure only the correct entry point is compiled for each platform. The irgo CLI handles this automatically.
App Configuration
The app/ directory contains your router setup and application configuration:
package appimport ( "myapp/handlers" "github.com/stukennedy/irgo/pkg/render" "github.com/stukennedy/irgo/pkg/router")func NewRouter() *router.Router { r := router.New() renderer := render.NewTemplRenderer() // Mount handlers handlers.Mount(r, renderer) return r}Handlers
The handlers/ directory contains your HTTP handlers. Group related handlers into separate files:
package handlersimport ( "myapp/templates" "github.com/stukennedy/irgo/pkg/render" "github.com/stukennedy/irgo/pkg/router")var renderer *render.TemplRendererfunc Mount(r *router.Router, rend *render.TemplRenderer) { renderer = rend // Pages r.GET("/", HomePage) r.GET("/about", AboutPage) // API routes r.Route("/api", func(r *router.Router) { r.GET("/users", ListUsers) r.POST("/users", CreateUser) })}Templates
The templates/ directory contains your templ templates. Organize by feature or page:
templates/├── layout.templ # Base HTML structure├── home.templ # Home page├── about.templ # About page├── components/│ ├── nav.templ # Navigation component│ ├── footer.templ # Footer component│ └── card.templ # Reusable card component└── users/ ├── list.templ # User list page ├── form.templ # User form └── item.templ # Single user itemStatic Assets
The static/ directory serves static files like CSS, JavaScript, and images:
static/├── css/│ ├── input.css # Tailwind source file│ └── output.css # Generated CSS (git-ignored)├── js/│ ├── htmx.min.js # HTMX library (downloaded by irgo new)│ ├── hx-ws.js # HTMX WebSocket extension│ └── app.js # Custom JavaScript (if needed)└── images/ └── logo.png # Static imagesThe output.css is generated by Tailwind during build. Add it to.gitignore and generate it as part of your build process.
Build Output
Built artifacts are placed in the build/ directory:
build/├── ios/│ └── Irgo.xcframework/ # iOS framework for Xcode├── android/│ └── irgo.aar # Android archive└── desktop/ ├── macos/ │ └── MyApp.app/ # macOS application bundle ├── windows/ │ └── MyApp.exe # Windows executable └── linux/ └── myapp # Linux binaryNext Steps
- Routing & Handlers - Deep dive into the router API
- Templ Templates - Learn template syntax and patterns
- Desktop Apps - Desktop-specific configuration
