UCloud logo UCloud logo UCloud
v2026.3.0
  1. UCloud/Core
  2. 1. Introduction
  3. 2. Projects
  4. 3. Accounting
  5. 4. Orchestration
  6. 5. Frontend
  7. UCloud/IM for Slurm-based HPC
  8. 6. Installation
  9. 7. Architecture and Networking
  10. 8. User and Project Management
  11. 9. Filesystem Integration
    1. 9.1. Inter-provider file transfers
  12. 10. Slurm Integration
    1. 10.1. Application Management
    2. 10.2. Built-in Applications
  13. 11. Reference
    1. 11.1. Configuration
    2. 11.2. CLI
  14. 12. Appendix
    1. 12.1. Built-in Application Index
  15. UCloud/IM for Kubernetes
  16. 13. Installation
  17. 14. Architecture and Networking
  18. 15. Filesystem Integration
  19. 16. Compute Jobs
    1. 16.1. Public Links
    2. 16.2. Public IPs
    3. 16.3. License Servers
    4. 16.4. SSH Servers
    5. 16.5. Job Audit Log
    6. 16.6. Virtual machines
  20. 17. Integrated applications
    1. 17.1. Syncthing
    2. 17.2. Integrated terminal
  21. 18. UCX applications
    1. 18.1. Hello world
    2. 18.2. Data binding
    3. 18.3. UI events
    4. 18.4. Component reference
    5. 18.5. API reference
  22. 19. Reference
    1. 19.1. Configuration
    2. 19.2. CLI
  23. Branding for UCloud
  24. 20. Branding and identity for UCloud
  25. H: Procedures
  26. 21. H: Procedures
  27. 22. H: Introduction
  28. 23. H: Auditing
  29. 24. H: Auditing scenario
  30. 25. H: GitHub actions
  31. 26. H: Deployment
  32. 27. H: 3rd party dependencies (risk assesment)
  1. Links
  2. Source Code
  3. Releases

Hello world

This is a minimal UCX application with one bound input and one button event.

package main

import (
    "fmt"
    "strings"
    "sync"

    "ucloud.dk/shared/pkg/ucx"
)

type helloApp struct {
    mu      sync.Mutex   `ucx:"-"`
    session *ucx.Session `ucx:"-"`

    Name    string
    Message string
}

func NewHelloApp() ucx.Application {
    return &helloApp{
        Name:    "UCloud",
        Message: "Click the button",
    }
}

func (app *helloApp) Mutex() *sync.Mutex      { return &app.mu }
func (app *helloApp) Session() **ucx.Session  { return &app.session }
func (app *helloApp) OnInit()                 {}

func (app *helloApp) UserInterface() ucx.UiNode {
    return ucx.Flex(ucx.FlexProps{Direction: "column", Gap: 8}).
        Sx(ucx.SxP(4)).
        Children(
            ucx.H2("UCX hello world"),
            ucx.InputText("name", "Name", "Type your name", "name"),
            ucx.Button("sayHello", "Say hello", ucx.ColorPrimaryMain).
                On(ucx.UiEventClick, func(ev ucx.UiEvent) {
                    app.Message = fmt.Sprintf("Hello %s!", strings.TrimSpace(app.Name))
                }),
            ucx.TextBound("message"),
        )
}

func (app *helloApp) OnMessage(frame ucx.Frame) {
    switch frame.Opcode {
    case ucx.OpModelInput:
        app.Name = strings.TrimSpace(app.Name)
        if app.Name == "" {
            app.Message = "Please enter a name"
        }
    }
}

func main() {
    ucx.AppServe(func() ucx.Application {
        return NewHelloApp()
    })
}

What is happening

  • Name and Message are exported fields, so they are serialized into the UCX model.
  • InputText(..., "name") binds to the Name field (Name -> name by default).
  • button clicks are handled with .On(ucx.UiEventClick, ...).
  • TextBound("message") renders the Message field.
  • ucx.AppServe(...) handles handshake, mount, model patching, and event dispatch.

First extensions

From here, most real apps add:

  • validation (errors.<field> paths),
  • collections ([]struct) displayed through ucx.List(...),
  • and backend calls via ucxsvc / ucxapi when submit is clicked.
Previous UCX applications
Next Data binding