Fyne — Structure#

Layout pattern#

Framework-specific (Interface-Root + Feature Packages + Internal Impl)

Fyne does not follow the conventional Standard Go Layout (cmd/internal/pkg). Instead, the root module (fyne.io/fyne/v2) is itself the primary public API surface — it contains only interfaces and data types, with zero rendering or implementation code. Feature domains (widgets, canvas objects, layouts, dialogs, etc.) each get their own top-level package, while every concrete implementation is hidden behind internal/. This “interface root + feature subpackages + implementation internal” pattern is characteristic of mature Go frameworks that must balance a stable public API against complex, platform-varying internals.

Directory map#

fyne/
├── *.go                  — Root package: interfaces (App, Window, Canvas, Driver, etc.) + core types
├── app/                  — Concrete App factory (app.New, app.NewWithID); many build-tag files
├── canvas/               — Canvas objects: Circle, Image, Line, Raster, Rectangle, Text
├── cmd/
│   ├── fyne/             — CLI tooling binary (deprecated; migrated to fyne.io/tools)
│   ├── fyne_demo/        — Interactive demo application showcasing all widgets
│   ├── fyne_settings/    — Desktop settings UI (appearance, theme)
│   └── hello/            — Minimal "Hello World" reference app
├── container/            — Layout containers: Border, Grid, HBox, VBox, AppTabs, Split, etc.
├── data/
│   ├── binding/          — Reactive data binding system (Go values ↔ widgets)
│   └── validation/       — Input validators (regexp, combined)
├── dialog/               — Standard dialogs: file chooser, confirmation, form, color picker
├── driver/
│   ├── desktop/          — Desktop-specific extension interfaces (hover, drag, system tray)
│   ├── embedded/          — Embedded driver extension
│   ├── mobile/           — Mobile-specific extension interfaces (swipe, pinch, rotate)
│   └── software/         — Software renderer driver
├── internal/             — All concrete implementations (not importable by user apps)
│   ├── animation/        — Animation loop engine
│   ├── app/              — App lifecycle internals (Lifecycle, CloudProvider)
│   ├── async/            — Internal concurrency helpers (goroutine queues)
│   ├── build/            — Build-time constants and constraints
│   ├── cache/            — Widget render caching
│   ├── color/            — Color utilities
│   ├── driver/
│   │   ├── common/       — Shared driver base (keyboard, event dispatch)
│   │   ├── embedded/     — Embedded driver implementation
│   │   ├── glfw/         — Desktop OpenGL/GLFW driver (63 files; primary desktop backend)
│   │   └── mobile/       — Mobile driver implementation
│   ├── metadata/         — App metadata (FyneApp.toml parsing)
│   ├── painter/
│   │   ├── gl/           — OpenGL painter (vector/text/image rasterisation)
│   │   └── software/     — Software (CPU) painter
│   ├── repository/       — Internal URI/storage repository
│   ├── scale/            — DPI/scale utilities
│   ├── svg/              — SVG parsing and rasterisation
│   ├── test/             — Internal test helpers
│   ├── theme/            — Internal theme defaults
│   └── widget/           — Internal widget base types (BaseWidget)
├── lang/
│   └── translations/     — Built-in i18n translation files
├── layout/               — Concrete layouts (Form, Grid, MaxLayout, Padded, etc.)
├── storage/
│   └── repository/       — Public storage/repository API (URI handling, file access)
├── test/                 — Public test helper package (for app authors to test their UIs)
├── theme/
│   ├── font/             — Bundled fonts
│   └── icons/            — Bundled SVG icons
├── tools/
│   └── playground/       — Fyne playground utility
└── widget/               — Main widget library (~695 exported functions; 60+ .go files)

Entry points#

BinaryPathPurpose
fynecmd/fyne/main.goDeprecated CLI tool for bundling, packaging, and building Fyne apps (migrated to fyne.io/tools/cmd/fyne)
fyne_democmd/fyne_demo/main.goInteractive demonstration of the full Fyne widget library and APIs; includes lifecycle and menu examples
fyne_settingscmd/fyne_settings/main.goDesktop GUI for configuring Fyne appearance settings (theme, scale)
hellocmd/hello/main.goMinimal “Hello World” reference app; primary quick-start example

Package organization#

  • Internal packages (internal/):

    • internal/driver/glfw — Desktop rendering via OpenGL + GLFW; the primary platform backend (63 files); CGo-dependent
    • internal/driver/mobile — Android/iOS driver
    • internal/driver/common — Shared event dispatch, keyboard routing
    • internal/painter/gl — OpenGL draw calls for vector shapes, text, images
    • internal/painter/software — CPU-only software rasteriser (used in tests and embedded mode)
    • internal/cache — Render object caching for performance
    • internal/widgetBaseWidget struct that all public widgets embed
    • internal/app — Lifecycle and cloud provider internals
    • internal/svg — SVG parsing for icon rendering
    • internal/animation — Frame-based animation scheduler
    • internal/async — Goroutine-safe function queue for UI thread dispatch
    • internal/metadataFyneApp.toml app metadata parsing
    • internal/theme — Default theme constants and font loading
  • Public packages (root + subpackages, no pkg/ directory):

    • Root fyne.io/fyne/v2 — Interfaces only: App, Window, Canvas, Driver, CanvasObject, Widget, Theme, Storage, Resource, etc.
    • app/ — Concrete app construction; bridges to internal/driver/glfw (desktop) or internal/driver/mobile (mobile) via build tags
    • widget/ — Complete widget library: Button, Label, Entry, List, Tree, Table, RichText, Calendar, and 40+ more
    • container/ — Container/layout types: AppTabs, Split, Scroll, Stack, Border, Grid, Max
    • canvas/ — Primitive canvas objects for custom rendering
    • layout/ — Standalone layout algorithms
    • dialog/ — Standard dialogs (file, confirm, form, color, custom)
    • data/binding/ — Reactive binding of Go primitives and lists to widget state
    • data/validation/ — Reusable validators for Entry widgets
    • driver/desktop, driver/mobile, driver/embedded, driver/software — Platform capability extension interfaces (e.g., desktop.Hoverable, mobile.Swipeable)
    • storage/ + storage/repository/ — URI-based portable file access abstraction
    • test/ — Public testing helpers for UI unit tests without a real display
    • theme/ — Theme implementation helpers, bundled fonts and icons
    • lang/ — i18n translation API
  • Layering: The architecture follows strict dependency flow: root interfaces → feature subpackages → internal/. User application code imports from the root and feature packages, never from internal/. The app/ package is the sole bridge that instantiates the concrete driver from internal/ and satisfies the fyne.App interface. This creates a clean separation where the public API can be tested headlessly (using the test/ package and software painter) without any CGo or display hardware.

Build system#

  • Build tool: Pure go build / go test; no Makefile found
  • Platform variation: Build tags and OS-suffixed files (_darwin.go, _windows.go, _mobile.go, _wasm.go, _xdg.go, _noos.go) are used extensively in app/ and internal/driver/glfw/ to select the correct implementation at compile time
  • Key targets:
    • go build fyne.io/fyne/v2/cmd/fyne — CLI tool (deprecated)
    • go build fyne.io/fyne/v2/cmd/fyne_demo — Demo app
    • go build -tags ci fyne.io/fyne/v2/... — Headless CI mode (uses software renderer, avoids CGo/GLFW)
  • CI: GitHub Actions with four workflows: platform_tests.yml (Ubuntu + macOS matrix), mobile_tests.yml, web_tests.yml, static_analysis.yml. Notably tests run with -tags ci,migrated_fynedo on Ubuntu (uses Xvfb) and -tags no_glfw,ci on macOS
  • Docker: None found; mobile builds handled externally via platform SDKs
  • CGo requirement: The GLFW/OpenGL desktop backend requires CGo (go-gl/gl, go-gl/glfw). The software painter and test driver are CGo-free, enabling headless testing on CI

Notable structural decisions#

  1. Root package as pure interface contract. Every exported type in the root fyne.io/fyne/v2 package is either an interface or a data/value type (no concrete implementations). This is a deliberate architectural choice that lets user code be fully decoupled from any rendering backend — the same UI code can run under the GLFW backend, the software test renderer, or a future WebGPU backend without change.

  2. No pkg/ directory; subpackages are the public API. Unlike many Go projects that segregate public API into pkg/, Fyne places all public packages as first-class top-level directories (widget/, container/, layout/, etc.). This mirrors the Go standard library’s style and makes import paths clean (fyne.io/fyne/v2/widget).

  3. internal/ as total implementation boundary. The entire rendering stack (GLFW, OpenGL, software painter, cache, SVG) lives in internal/, making it refactorable without any public API breakage. The 32 packages under internal/ vs. 15 top-level feature packages illustrates how much complexity is hidden.

  4. Build-tag–driven platform selection. Rather than runtime dispatch for platform differences, Fyne uses compile-time file-suffix and build-tag selection. The app/ package alone has 18+ platform-variant files. This is a consistent, idiomatic Go choice that keeps binaries lean (no unused platform code) but makes the codebase harder to navigate without knowing the conventions.

  5. Deprecated cmd/fyne as a transitional artifact. The cmd/fyne/ binary is explicitly deprecated (prints a notice at startup) and points users to fyne.io/tools/cmd/fyne. Keeping it in-tree during the transition is a conscious compatibility choice and signals that Fyne is moving tooling to a separate module — a sign of project maturity and modular discipline.