Releases
From v0.50.0, vuka, ui, web and the vuka command (and from v1.0.0 vukavet) are released together under one version: a release is a set, and vuka v1.0.0 means all of them at v1.0.0. The set keeps the compatibility promise, which from v2.0.0 covers the /v2 modules. An app requires vuka, ui and web at the same version; vuka version shows the set and warns when an app's go.mod mixes sets, and vuka upgrade moves an app from one set to another, running the vuka fix rewrites in between. Patch releases come weekly, security fixes at once, features in minor releases with upgrade notes. See Versions and compatibility.
go install github.com/vuka-lang/vuka/cmd/vuka/v2@latest
vuka upgradeReleases before v0.50.0 were tagged module by module; their headings name each module's version, and each states the runtime its generated code needs — the github.com/vuka-lang/vuka package your module requires.
v2.5.0 — 2026-10-24
- Hooks on generic shapes.
@ui.Mount,@ui.OnChangeand@ui.Loads("group")on a method of a generic component compile and run per instantiation: they go into itsLiveSchema, now written as a method of the generic type (func (t *Table[T]) LiveSchema(…)), soTable[Task]andTable[User]on one page each mount. A hook attribute on a method of a type that isn't live is E0130 instead of being lowered as a call of the islands'ui.Mount(props)(#87). - Field attributes on generic components.
@ui.URL(with.Default),@ui.Bind,@ui.Deferand thevalidaterules work on a generic live component's fields, each instantiation keeping its own URL parameters under itsurlKey. E0206 now covers only a generic type that isn't live, whose attributes would be registered for the type at package level (plain value attributes,ormmodels) (#96). - Context processors in folder pages. A page under
pages/— a route group's(admin)and a parameter folder's[id]included — readsrequest,permsand the app's processors' variables by name: main reaches those packages only through the generatedpages/route.go, which the discovery now follows, also beforeroute.gois first written. Hover and completion work there too (#94). - An app processor importing the app's packages. A processor whose package imports another package of the module — one with shapes, or one the pages import too — no longer breaks that package's build: a processor's package and its imports don't get its variables (reading them would be an import cycle) and are compiled first. Where processors' packages and their readers still need each other, the new E0428 names the processor and the cycle instead of an unrelated
could not import(#95). - One spelling for request context in vuka files.
vuka vet's W0402 now reportsauth.Can(ctx, "x"),auth.Current(ctx),auth.Current(ctx).Can("x")andweb.Request(ctx)(read through whatrequesthas) in markup and Go of.vukaand.vuka.htmlfiles, whereperms.Has("x"),userandrequestgive the same, tracked; whenmaindoesn't listauth.Contextorweb.RequestContext, it says to.vuka fix ctx-varsrewrites them and drops the imports left unused, and the editor offers the same quick fix. W0403 acceptsperms.Has("x")in the event as its check. Plain.gopackages keepauth.Can; from 3.0 the direct calls are a compile error in vuka files (#97).
v2.4.0 — 2026-10-23
- Context processors.
web.ContextProcessors(…)inmainlists the functions that give every template request-level values: each a plainfunc(ctx, deps…) (S, error), each exported field ofSa variable. Built in, and listed the same way:web.RequestContext(request),auth.Context(user,perms),web.MessagesContext(messages, withweb.Flash),web.CSRFContext(csrfToken),ui.PageContext(page). A processor runs only when a render reads one of its variables, once per request or live event; reads are tracked, so a staying layout showingrequest.Pathupdates that spot and stays.web.Var[T](ctx, "name")reads one in Go,web.WithVarsgives other values below a context,web.RefreshVarsruns a processor again,web.Auth(p, gates…)guards one, andweb.Browser(p)(withweb.Personalfor one reading the visitor) lets islands read it; aweb.NotForBrowservalue such asauth.Permsis never sent. See context processors. - Live renders follow the variables. Each read is recorded against the component rendering it, and a processor's inputs with it (
web.RecordInput;web.Requestrecords the URL,auth.Currentthe identity and its permission version): an event, a broadcast or a navigation renders again only the components whose variables changed, and results carry across a live connection's pages while their inputs hold. - Permissions that change under a live page. auth keeps a permission version per user, bumped by
Refresh, sign-out,auth.Impersonate/auth.StopImpersonatingandRevokeUser;auth.Contextgivesuser,perms(Has, with wildcards) andactor, the real user while impersonating. - Flash messages and CSRF tokens.
web.Flash(ctx, level, text)(a signed cookie over HTTP, the next render on a live page) feedsmessages;web.ValidCSRFTokencheckscsrfToken. - Testing with variables.
viewtest.With(vars…)andviewtest.Context(ctx, vars…)(web/v2/viewtest) give pages and contexts their own values. - Variables by name in templates. The compiler reads
main's list, and a bare name in a shape, its script or a.vukafile that names nothing else reads the variable, typed:{me.Name}isweb.Var[*users.User](ctx, "me").Name. Every package a main imports reads them, and one imported by several mains reads what all give (E0422); libraries read them withweb.Var. Errors for a clash (E0421), a read without actx(E0423), a typo with a suggestion (E0424) and a list entry that is no processor (E0425). - vet for context processors.
vuka vetwarns about a field or local shadowing a variable (W0401),web.Request(ctx)in markup whererequestwould do (W0402), a control shown behindperms.Has("x")whose event checks nox(W0403) and a variable stored in a staying layout'sLoad(W0703); vukavet refuses aweb.Browserprocessor reading the visitor withoutweb.Personal(E0426) and checks everyweb.Varread the app links in against its list (E0427). - Context processors in the editor.
vuka lspcompletes the variables and their fields, hover gives a variable's type and processor (from users.Context (users/context.go)), go to definition jumps to the processor and its entry inweb.ContextProcessors, and variables have a semantic token type of their own,vukaContextVar. - Scaffolds list the processors.
vuka newwritesweb.ContextProcessorswith the built-in processors intomain, so they are visible and removable. - URL state on components. A component's field marked
@ui.URL("tab")is filled from the page's query as it renders and whenever the URL changes (a patch, back, forward); an event assigning it patches the page's URL, the other parameters kept, in place of the current history entry. A prop the parent passes wins, then the URL, then@ui.URL("page").Default(1)or the zero value; a field holding its default leaves the parameter out. A bare@ui.URLreads the route's path parameter of the field's name, andvukareports a folder page rendering such a component without that parameter (E0340). See URL State. urlKeykeeps two components apart.<Table urlKey="requests"/>keeps that instance's parameters as?requests.page=;vukavet's newurlstatecheck warns when two components one markup renders keep one parameter (W0307).web.Queryfrom events.web.Query.Set(ctx, "status", "open"),Del,Update(ctx, func(url.Values))andGetedit the live page's query as one patch per event, without a history entry unless givenweb.Push. AnUpdatetakingweb.URLParamsitself keeps a page mounted while its components follow the URL; a Live page's field marked@ui.URL("q")binds?q.ui.JS.PatchReplaceand livetest'sBack,ForwardandHistoryare new.- URL state in the editor.
vuka lsphovers@ui.URLwith the parameter, its default and itsurlKeyform, and completes the package's keys inside@ui.URL("…").
v2.3.0 — 2026-10-23
Shape outline and sticky scroll.
vuka lspgives a.vuka.htmlshape's struct the whole file down to the end of its markup, holding its fields, methods and the markup's elements (section#todos.list), so sticky scroll keeps the struct pinned over the markup; the methods the markup compiles to, and symbols that map nowhere, leave the outline. The Go header folds as one. See keeping the struct in view.Format Selection.
textDocument/rangeFormattingfor.vukaand.vuka.htmlfiles:vuka fmt's changes on the selected lines only.Markup completion. Every ARIA attribute with its values and the WAI-ARIA roles; the event handlers each element fires (
onSubmiton a form,onCloseon a dialog, playback events on media), each saying the handler forms;ref, and the file's refs insideui.Ref("…"). See completing attributes, events and refs.Keyed loops. In a range loop over items with an
ID-like field, the first element completes withkey={item.ID}, andforon a markup line offers a keyed loop, so W0102 doesn't come up. See keying a loop's items.VS Code extension 0.8.0. Defaults that make Tailwind CSS IntelliSense find classes in shapes (
class="…",class={…}strings,…Classhelpers) and turn Emmet on in.vuka.htmlfiles. See Tailwind CSS.Shape names coloured by what they read.
vuka lspgives the names in a.vuka.htmlfile's markup semantic tokens of their own — a prop, server state, browser state, an event, a component tag, a template local — after gopls's in the legend; the VS Code extension maps them to scopes themes colour apart. See telling shape names apart.Hover on holes and events. A hole's name says what it reads, its type and where it is set (
set in mount (@ui.Mount)); anon…attribute says whether it runs on the server and patches the page, or runs in the browser. See seeing what a name reads.Component tags. Completion in a component's tag lists its attributes with their types, required ones marked (a function's parameters; a struct's props may be left out); hover on the tag shows them and links its file. See writing component tags.
Routes in the editor. A code lens above each page and handler (
GET /orgs/{org} · live · layout org.Layout · guard org.Guard),urlschains and literalhrefs as links and definitions to the page, references on a page listing them, and renaming a page file or folder underpages/renaming theurlschains naming it. See following routes and renaming pages.Refactoring shapes.
vuka lspextracts a selection of a shape's markup into a component of its own (Extract component…): a shape file in the script form, in_parts/beside a page or in the shape's package, its props the fields, variables and methods the selection reads, typed by the package's type check, and the tag passing them in the selection's place. Move to the logic file moves a shape's methods, one or all butTitleand its hooks, from its script to the.vukafile beside it, imports following. Quick fixes for W0102 (a key from the item's ID-like field or the index), W0703 (the page's title read in the layout's markup; a current link marked withui.Link'sactive), E0155, E0142, E0329 and W0701 (on apages/tree'sroute.go:pages.Routes()passed to the owning main'sweb.New, asvuka fix routesdoes). See refactoring.<script lang="go">shapes. A.vuka.htmlfile's Go goes in a<script lang="go">, the file's first element, and its markup follows</script>; the file is HTML to every HTML tool. Before and after:htmlpackage counter type Index struct{ count int } func (p *Index) Add() { p.count++ } <button onClick={Add}>{count}</button>html<script lang="go"> package counter type Index struct{ count int } func (p *Index) Add() { p.count++ } </script> <button onClick={Add}>{count}</button>The end is found by Go's tokens, so
</script>in a string or comment doesn't end it (E0156 when nothing does); one script per file, first (E0157). Diagnostics,vuka lspand source maps keep the file's positions. The header form still compiles in 2.x and is removed in 3.0;vukavetreports it (W0107), the editor offers a code action, andvuka fix shape-scriptorvuka fmt -rewriteconverts files. Scaffolds, the docs, the ui kit and the examples use the new form. See laying out the file.<style>in a shape.<style scoped>after the markup is scoped to the shape's elements by thedata-vk-sattribute, an id from the package and the struct's name (:global(…)escapes it; slot content keeps the caller's scope); a plain<style>is the app's global CSS, bundled once even when two shapes hold the same stylesheet. See scoped stylesheets.vuka fmtformats the whole shape. The Go as gofmt does, the markup indented two spaces a level with its statements and holes gofmt'ed and long tags wrapped an attribute a line, void and childless component tags closed (<br />,<ui.Badge />), and the CSS of a component's<style>— changing only whitespace that doesn't render.vuka.toml's[fmt]table sets thewidth(100) and turns on Tailwind class ordering (tailwind = true, off by default). New flags:-checkfor CI,-rewritefor the script form. Format-on-save and Format Selection use the same rules. See formatting shape files.Scoped slots. A slot field of a func type returning
ui.Node(Row func(T, int) ui.Node) takes<slot:row let={t, i}>…</slot:row>: the content is the function's body,letnames its values with the field's types, generic components included (<components.List[Task]>). See passing values to a slot.Repeated slots. A slice-of-structs field (
Columns []Column[T]) takes one element per<slot:column …>, in order: attributes set the struct's fields, the content its one func orui.Nodefield.ui.Tableandui.DataTabletake their columns this way, their Go API unchanged. See repeating a slot.Slot fallback content. In a component's own markup,
<slot:actions>…</slot:actions>renders Actions, or the content when the caller left the slot out (ui.SlotOr);ui.Has(node)reports whether a slot was filled, false for nil and white space. See giving a slot fallback content.Required slots. A field tagged
vuka:"required"is filled at every tag, else E0158. See requiring a slot.Slot errors name the slot. A slot the component doesn't have suggests the nearest (
did you mean <slot:actions>?); aleton a slot that takes no values, or naming more than it passes, says so.Slots in the editor.
<slot:inside a component's tag completes its slots with their types (scoped and repeated ones with alet); alet's names are template locals for the slot's content, coloured as such, and hover on one shows its type. See writing component tags.Text for a node. Quoted text setting a
ui.Nodeprop is that text:<ui.Card title="Members">.Closing a generic tag.
</List[Task]>closes<List[Task]>as</List>does, in the compiler and invuka fmt.
Fixes
- A shape being written — its struct and no markup yet, or a first tag half typed — crashed the compiler (
index out of range [-1]), and with itvuka lspon every keystroke until the editor stopped restarting it. It is E0148 now, in both forms. vuka lspno longer exits on a compiler panic: the file gets an E0001 diagnostic with the panic's message, the stack goes to the server's log, and the server keeps serving.vuka add pagein an app whosemaindidn't passpages.Routes()to its app yet — one made with templ views or as an API, or any app without apages/tree — wrote the page and left it unserved. It now adds thepagesimport andpages.Routes()to theweb.Newof the main that ownspages/, inmain.goormain.vuka(into the option listweb.Newspreads, when it spreads one), and leaves a main that passes it already as it is;vuka add moduledoes the same when it writes the module's page. When it can't tell which main serves the pages, or can't find the call, it prints the line to add and where.vuka fix routesmakes the same change, and W0701 points to it.vuka lspdrops gopls'sgo.moddiagnostics aboutmalformed import path ".../(admin)"(and[id]) for Go files in route-group and parameter folders; those packages are still type-checked through the packages vuka maps them to.
v2.2.0 — 2026-10-23
An admin shell — a menu of links in collapsible groups, a header with the page's title and breadcrumbs, the page below — stays across navigations and follows the page. See a header that follows the page and the current group.
- Breadcrumbs from the page. A page with
Crumbs() []ui.Crumbgives its trail, eachui.CrumbaLabeland anHref(""for the page itself), read in a layout withui.PageCrumbs(ctx)asui.PageTitle(ctx)reads its title; web reads it when it readsTitle, andui.WithPageCrumbssets it. A layout that stays renders its markup again for every page, so a heading and crumbs read there are the new page's while itsLoaddoesn't run again. - The current link's group. An element marked
data-vk-active-withinis"true"while it holds the current link (ui.Link'sactive) and""when not; a<details>so marked opens when the current link comes inside it, as the page loads and on navigation, and is the visitor's to close. - A layout reading the page's title or breadcrumbs in its
Load, or in whatLoadcalls, reloads on every navigation (web.ReloadLayout), as one reading the request does; vukavet's W0703 says so and points at reading them in the markup.
NOTE
Upgrading: a layout storing ui.PageTitle(ctx) in its Load showed the first page's title after 2.1.0's navigations; it now loads on every navigation, and vukavet warns. Move the read to the markup and it stays.
Fixes
vuka newwrites apackage-lock.jsonbeside each frontend'spackage.json(the Vue, React and Svelte frontends and the islands'web/), and the first install runsnpm cifrom it: npm 10, which Node.js 20 and 22 ship, crashed resolving those packages from scratch (Cannot read properties of null (reading 'edgesOut')). Before running npm, vuka checks its version: npm 10 installing from a lockfile is a warning, and npm 10 installing without one, or adding packages, stops with E0610 and the fix,npm install -g npm@11.vuka doctorshows npm's version. pnpm, yarn and bun aren't checked.- A
<details>the visitor opened or closed keeps that state when a render leaves itsopenas it was; in 2.1.0 the render of a layout that stays, on every navigation, closed the menu groups the visitor had opened. - A
.vuka.htmlfile imports a sibling file's package only for a real selector (time.Now()): a string or a comment naming it,"any time.", no longer adds an import the go command reports unused. - Assigning several tracked fields at once compiles in every form: fields of a tracked struct (
c.q.Path, c.q.Page = "", 1), a field beside a field of another (c.note, c.q.Path = "gone", ""), and values with no type of their own,nilor-1into anint64, which take their place's type. See selectors and mutable values. delete(p.items, k),clear(p.items)andcopy(p.slots, src)on a tracked field are writes of it, so the session sees the change; in 2.1.0 they changed the value unmarked, and the page kept its last render.- A component's prop of type
ui.JSChain(orany) takes anon…attribute's statements,<Chip onClick={manage = !manage}/>, as an element's does, to forward to its button; a prop of a func type is E0101 with the prop to declare. See handing a click to a child.
v2.1.0 — 2026-10-23
Folder routes learn three folder conventions, so a page tree can say which pages share a shell, which share a document, and which files are no page. See Folder routes.
- Route groups. A folder in parentheses,
pages/admin/(console)/, adds no segment to the URL; its_layout.vuka.html, guard and middleware apply to the pages inside it alone, nested inside the layouts above it. A sign-in page atpages/admin/auth/login.vuka.htmlis then/admin/auth/loginoutside the admin shell and its guard, besidepages/admin/(console)/index.vuka.htmlat/admin. The go command sees a group asgroup_console/; typed URLs leave it out (urls.Admin.Auth.Login);vuka routesnames its layout and guard;vuka add page /admin/(console)/membersmakes a page in it. - Root layouts. A layout with no layout above it is a root layout, the document of the pages below it: with no
pages/_layout.vuka.html, each top-level folder or group may have its own, also below a parameter folder (pages/[lang]/_layout.vuka.html). Each route's root layout is invuka routes -json(root), in web'sRouteInfo.RootLayout, and on the page asdata-vk-root; in-app navigation between two roots is a full page load, under one root a patch as before. - Private folders. A folder of
pages/named with a leading underscore,pages/_parts/, routes nothing: its components and helpers are a package the pages import, by its Go nameexample.com/app/pages/private_parts. - Layouts that stay. A live page navigating to another page under the same folder layouts keeps them: from the outermost down to the first that differs (another layout, or other path parameters), a layout's
Loaddoesn't run again, and its elements, scroll, client state, live components and islands stay in the page; only what is below the deepest shared layout is swapped. Guards run on every navigation all the same. A layout whose methods read the request —web.Request, its URL or query, an*http.Request— loads and renders on every navigation as before:vukaregisters it with the newweb.ReloadLayout, and vukavet warns (W0703). See layouts that stay. - The current link.
ui.Link'sactive("exact"or"prefix") andactiveClassmark the link matching the address witharia-current="page"and the class, in the browser, on load, after every navigation and on back and forward: a layout's menu follows the page without reading the request. See the current link. - Prefetch. A
ui.Linkthe browser loads as a page is fetched ahead on hover, focus or touch (prefetch="viewport": once in view;prefetch="off": never), same-originGETs only, none when the visitor saves data, kept 30 seconds. A prefetched live page's session waits parked for the page to open, so its mount hook runs once. See prefetch. - A navigation's reply carries the new page's title, which the runtime sets on the document, and resets the scroll of the page's
<main>along with the window's. - ui:
ui.Keyed(key, node)scopes the stateful components in a node as an element'skeydoes, without markup;live.Route.Keepkeeps a navigation's instances in place as a patch does. - New diagnostics: E0722 two routes on one URL told apart only by a group, naming both files; E0723 a name in parentheses that is no group; E0724 the home page outside the top-level groups' root layouts.
- Go in route folders. A
.gofile in a group or a[id]folder — logic or_test.go— is the folder's package: vuka copies it, with a line directive naming it, where the go command sees the folder (group_console/,param_id/), forvuka build,run,test,vetandgen, andvuka lsptype-checks it there, its errors and definitions at the real file. So does one beside Vuka source in a private folder. In 2.0.0 each was E0716, which now names only a.gofile of another package than its folder's, or one named[id].go. The Go-name directories are the overlay's alone: vuka no longer makes emptyparam_id/,group_admin/orprivate_parts/directories in the source tree (vuka testandvetmake them for their run only), and removes empty ones an older vuka left;vuka gen -inplacestill writes its files there. - Route files on disk under
vuka run.vuka runandvuka run -watchwritepages/route.goandpages/urls/urls_gen.goto disk when their text changes (the overlay holds the same), so an editor resolves thepagesandpages/urlsimports of hand-written code; in 2.0.0 they were in the build's overlay alone. They are generated: gitignore them. Nothing elsevuka rungenerates is written. - Upgrading: a folder under
pages/named(x)or_xmeant nothing before and is a group or a private folder now; a private folder holding Vuka source compiles asprivate_x, so its importers name that path. The vuka command of v2.1.0 needs web v2.1.0: it registers a layout reading the request withweb.ReloadLayout, and the full-load navigation between root layouts and the layouts that stay come with it.
Fixes
- A page's
Post,Put,PatchorDeletehandler may take a provided dependency as a pointer beside its body struct (Post(ctx, store *Store, form PetForm)); 2.0.0 read the pointer as a second body, E0709. A page whose markup sends one of those names as an event is E0709 now, rather than the event being taken as the handler. - The constructor Vuka writes for a type whose fields differ only by case (
Greeter,greeter) gives each its own parameter. p.rows = load()?on tracked state sets it once the call succeeds, asrows := load()?; p.rows = rowswould; andp.a, p.b = p.b, p.aassigns tracked fields too. Both were E0150.- A stateful shape's value in a hole (
{Card{…}},{c}) renders as the component, by its address; one whose address can't be taken is E0128 instead of text printed withfmt. - Statements among a component tag's children (
label := …) run before its<slot:x>content, which may read them. - A component attribute reading browser state (
<ui.Show when={tab == "b"}>) is lowered as an element attribute's is, once the markup's bare names are known; one whose prop can't take a state is E0125, not a Go type error. vuka lspoffers no completion in markup text or a quoted attribute's value: a sentence ending in a package's name (…failing to sync.) no longer gets Go items whose acceptance imports the package.- Another package's model reads as one of this package's:
users.User.Objectsisorm.Objects[users.User]()(in 2.0.0 it was a method expression oform.Model'sObjects), andusers.User.Namethe typed field. - A shape's field named like a built-in (
Result,Option) is the field in its markup. - A component attribute names an initialism's field in lowerCamel:
idforID,uidforUID. - A
{…}naming a value in a<style>is E0128: a stylesheet has no holes, andstyle:--x={v}sets a CSS variable. vuka fmtleaves a.vuka.htmlheader's one-line struct as gofmt writes it.- A
_test.gofile writing a page's tracked state is E0155 naming the_test.vukafile to move it to, where the write is lowered. - A shape's methods may live in a
.vukafile beside its.vuka.htmlfile: reads and writes of its tracked server state (p.rows = v,len(p.rows),p.n++,p.rows[i].Done = true) and writes of itsui.Statefields are lowered there exactly as in the header. In 2.0.0 only the header's methods were, so a method beside the shape failed with a Go type error (E0002) naminguigen.Assign. See where its methods live. - A
.gofile reading or writing tracked state — which the compiler can't rewrite there — is now E0155, naming the field, the shape file declaring it and the function, and saying to move the method to a.vukafile or into the header. vuka vetruns vukavet's checks by default. In 2.0.0 plainvuka vet ./...ran go vet's own analyzers, so vukavet's reports (a live list without keys, W0102, among them) appeared only with-vettool=$(go tool -n vukavet). It now uses the app'sgo tool vukavetwhen itsgo.moddeclares the tool, else avukavetbesidevukaor onPATHof its version, else one it builds at its version into the user's cache, and says on stderr when there is none.-vettool=…still overrides it;VUKA_VUKAVETnames one, orofffor go vet's own analyzers only. An app that passedvuka vetmay now see vukavet's warnings.- A folder page's unexported dependency fields are injected: a page
pages/route.gobuilds with&T{}gets each unexported field of a provided type (users *users.Service) set for the page, its mount hook and itsPost,Put,PatchandDeletehandlers, as a page-backed island's are; so do a live folder page and a folder's layouts and guards. In 2.0.0 the field was nil unless the page had aNewTtaking the dependency. Tracked state,ui.Statefields, exported props and fields of types nothing provides are left alone; a dependency field the URL would bind too is E0419. See dependency fields. Needs web v2.1.0. - A composite literal setting a shape's tracked state,
Badge{count: 0}or&Badge{Label: "a", count: n}(keyed or in order), in a.vukafile or a shape's header sets the field's tracked value; in 2.0.0 it was a Go type error naminguigen.Assign. In a.gofile it is E0155, naming the literal and saying where to move it.
v2.0.0 — 2026-10-23
vuka 2.0 has one way to write each part of a UI: markup lives in .vuka.html files, each declaring the one struct it renders above its markup; a page is a file under pages/, its path its URL; a hook is a method marked with its attribute; and a handler's parameters are filled by their types. Two vuka apps now look alike, and the docs teach one form of each thing. The design and its decisions are in the one-way RFC.
Every module of the set moves to a /v2 path, and the orm with it:
| 1.x | 2.0 |
|---|---|
github.com/vuka-lang/vuka | github.com/vuka-lang/vuka/v2 |
github.com/vuka-lang/ui | github.com/vuka-lang/ui/v2 |
github.com/vuka-lang/web | github.com/vuka-lang/web/v2 |
github.com/vuka-lang/orm | github.com/vuka-lang/orm/v2 |
github.com/vuka-lang/vuka/cmd/vuka | github.com/vuka-lang/vuka/cmd/vuka/v2 |
github.com/vuka-lang/vuka/cmd/vukavet | github.com/vuka-lang/vuka/cmd/vukavet/v2 |
The runtime is v2.0.0: generated code needs github.com/vuka-lang/vuka/v2 at v2.0.0. A 1.x app keeps building on its 1.x requirements; the compatibility promise now applies to the v2 set.
go install github.com/vuka-lang/vuka/cmd/vuka/v2@v2.0.0One struct per .vuka.html file
- A
.vuka.htmlfile is a Go header — package clause, imports, one struct, its hooks and methods — then markup, from the first line starting with<. The struct no longer lives in a sibling.gofile, and a file holds no second template: a partial is its own file, used as a tag. .vukaand.gofiles are logic only: services, models, helpers,main. Markup anywhere else is E0151; a template file declaring no struct is E0152, a second template in one E0153.- A file whose markup is one island tag is the page that island backs; its struct's exported fields are the island's props (E0154).
- A struct's fields say what they are: exported fields are props (on a page, filled from the path segment of their name, else the query), unexported fields are server state the page tracks — or dependencies, when their type is a pointer or interface the container provides — and
ui.State[T]fields are browser state. A struct is live when it embedsui.Live, declares a hook or wires a server handler in its markup. - Writing
ui.HTMLby hand is W0106; it stays the compiler's output.
Client state is a field
ui.State[T] is declared as a field (or a package variable in a logic file), read as a plain variable in markup and written by assignment in an on… attribute: onClick={open = !open}, onClick={tab = "env"; Save()}. Its Go API is Get and Set. ui.UseState, ui.UsePageState, Toggle, Inc, Dec, Reset, Derived, At and ui.Assign moved to github.com/vuka-lang/ui/v2/uigen, the package generated code calls; vukavet reports a hand-written use (W0105) (Client state).
Folder routes
- A path parameter is a bracketed name:
pages/pets/[id].vuka.htmlis/pets/{id}, a[employer]/folder holds a segment shared by a layout, several pages and anapi/subtree, and[path...]is the catch-all. The parameter's type andvalidate:rules are the field of its name on the struct that reads it.params.gofolders and theirParamsstructs are gone (E0714). - A folder's layout is its
_layout.vuka.html(E0715).guard.goandmiddleware.gostay Go. - The
vukacommand writes one file,pages/route.go, whoseRoutes()is the tree's registration;mainpasses it toweb.New. A 1.xpages_gen.goin its way is E0718. - Pages are declared under
pages/only: a page registered with a decorator or aweb.Routescall is E0720, a page underpages/whose markup is written in Go E0721, and a hand-writtenweb.PageRoute,LayoutOf,GuardOf,UseOforReceiverW0702.app.Getand the other route methods stay, for APIs in Go. - A
pages/directory beside apackage mainis that main's routes, so a module holds several apps (Several apps in one module).
Hooks are attributes
@ui.Mount, @ui.OnChange and @ui.Loads("group") on a method, and @ui.Bind, @ui.URL and @ui.Defer on a field, are the only way to declare a hook. A method named Mount or Changed is an ordinary method — and, being exported, an event the browser can call (E0337); the constructor hooks OnMount, Loads and OnChange on ui.Live are E0338. A hand-written LiveSchema method is reported by vukavet; the compiler still writes one (Hooks).
Parameters by type
A hook, a page handler, a live event and an endpoint read their parameters by type: context.Context, a struct (the form or JSON body), url.Values, a scalar (the path segment of its name, else the event's value), *http.Request, http.ResponseWriter, the signed-in user, and any type registered with app.Service(NewX) or web.Provide. A parameter with no source is a start-up error naming it. web.Params is gone: the command records parameter names from the source. @web.Service and the inject: tag are E0420; a service is a struct with a constructor, registered in main (Parameters, Dependency injection).
Removed
- The diagnostics of retired forms are gone with them: E0140 (a template file with no type to render), E0145 (a template named like an element) and W0104 (an exported template without a doc comment). Their codes are not reused.
- The conformance suite's hand-written Go twins are deleted: each app of
examples/conformanceis written the one way and compared with the Go it ejects to, with and without the generated speed-ups. - vuka's
internal/format,internal/loadandinternal/tspropsaretoolchain/format,toolchain/loadandtoolchain/tsprops, for the command and the editors; they are outside the promise. - The docs show one form of each sample; the Vuka / Go switch is gone.
Moving an app from 1.x
There is no migration command: an app moves to 2.0 by hand, and the compiler guides it. Each retired form is an error whose help names the one way to write it, and each error's page shows the change, wrong and right.
1. The import paths. Move go.mod to the v2 set, then rewrite the imports in the app's source:
go get github.com/vuka-lang/vuka/v2@v2.0.0 github.com/vuka-lang/ui/v2@v2.0.0 github.com/vuka-lang/web/v2@v2.0.0
go get github.com/vuka-lang/orm/v2@v2.0.0 # when the app uses the orm
go get -tool github.com/vuka-lang/vuka/cmd/vuka/v2@v2.0.0 github.com/vuka-lang/vuka/cmd/vukavet/v2@v2.0.0
find . \( -name '*.go' -o -name '*.vuka' -o -name '*.vuka.html' -o -name '*.templ' \) -not -path './node_modules/*' -print0 |
xargs -0 perl -pi -e '
s#github\.com/vuka-lang/vuka/cmd/(vuka|vukavet)\b(?!/v2\b)#github.com/vuka-lang/vuka/cmd/$1/v2#g;
s#github\.com/vuka-lang/(vuka|ui|web|orm)\b(?!/v2\b|/cmd/vuka)#github.com/vuka-lang/$1/v2#g'The rewrite also changes github.com/vuka-lang/... in comments and string literals, links included; read the diff. Then drop the 1.x requirements and tools from go.mod (go mod edit -droprequire github.com/vuka-lang/web, and so on, -droptool for the old command and vukavet). Sub-packages follow their module: github.com/vuka-lang/ui/validate is github.com/vuka-lang/ui/v2/validate, github.com/vuka-lang/web/authgithub.com/vuka-lang/web/v2/auth.
2. Pages into pages/, as .vuka.html files. A page's struct moves from its .go file into the header of its template, the template moves to the page's path under pages/, and a params.go folder becomes a bracketed one, its field moving onto the struct that reads it:
1.x 2.0
pages/pets/pet/params.go Params{Pet} (gone)
pages/pets/pet/index.go type Index pages/pets/[pet]/index.vuka.html
pages/pets/pet/index.vuka.html (one file: struct, methods, markup)
pages/layout.go + layout.vuka.html pages/_layout.vuka.html
pages/pages_gen.go pages/route.go (written by vuka)- // pages/pets/pet/index.go
- package pet
-
- type Index struct {
- Params
- store *store.Pets
- }
-
- // pages/pets/pet/index.vuka.html
- package pet
- <h1>{store.Name(Pet)}</h1>
+ // pages/pets/[pet]/index.vuka.html
+ package pet
+
+ import "example.com/shop/store"
+
+ type Index struct {
+ Pet int64 `validate:"min=1"`
+ store *store.Pets
+ }
+
+ func NewIndex(s *store.Pets) *Index { return &Index{store: s} }
+ <h1>{store.Name(Pet)}</h1>A partial (a func template after the main one) becomes its own .vuka.html file, a struct whose exported fields are its parameters, used as a tag; a component whose struct was in Go moves the same way. JSX in a .vuka file moves to a .vuka.html file beside it.
3. Hooks as attributes.
- func (p *Search) Mount(ctx context.Context) error { … }
- func (p *Search) Changed(ctx context.Context, c ui.Changed) error { … }
+ @ui.Mount
+ func (p *Search) mount(ctx context.Context) error { … }
+
+ @ui.OnChange
+ func (p *Search) changed(ctx context.Context, c ui.Changed) error { … }A LiveSchema method or constructor hooks become the same attributes, and a field's l.Field(&p.Q, ui.Bind{…}, ui.URL("q")) becomes Q string @ui.Bind{…} @ui.URL("q").
4. main passes the routes. The blank import of the pages package becomes a call, and services are registered on the app:
import (
- _ "example.com/shop/pages"
+ "example.com/shop/pages"
- "github.com/vuka-lang/web"
+ "github.com/vuka-lang/web/v2"
)
func main() {
- a := web.New()
+ a := web.New(pages.Routes())
+ a.Service(store.NewPets)
log.Fatal(a.Run(""))
}5. Build, and follow the errors. vuka build (or go vet -vettool=$(go tool -n vukavet) ./... in a Go app) reports each form still in the 1.x shape, with its fix: E0151–E0154 for markup, E0714–E0716 and E0718 for folders, E0720, E0721 and W0702 for pages outside pages/, E0337 and E0338 for hooks, E0420 for dependencies, W0105 and W0106 for the compiler's own API written by hand. Then run the tests.
Known issues
vuka upgradedoesn't rewrite 1.x import paths; use the recipe above.- A hole,
{expr}, inside<script>or<style>is written out literally, not evaluated. Pass a value to a script through an element's attribute (data-total={total}) and read it there.
v1.5.0 — 2026-10-22
The development toolbar starts as a small right-edge indicator. Hover nearby or focus it to reveal the handle; click to open the full drawer. Touch devices keep a larger tap target, and reduced motion is respected.
Live tables now display partial checkbox selection using the browser's indeterminate state on initial render and subsequent patches.
Request panic recovery now covers middleware, custom routers and page rendering as well as compiled handlers. Uncommitted responses answer a safe 500 through
OnError; panic details and stack traces stay in the server log. A broken error handler falls back to a generic 500.A panic after a response is written or flushed aborts that response, preserving
http.ErrAbortHandler. HTTP/2 push, streaming and WebSocket upgrades remain available. Hijacked connections are closed on unexpected panics.A panic during a live render or guard closes only the affected socket with code 1011 and a generic reason, discarding its session. Startup errors and panics in application-created goroutines retain their existing behavior.
v1.4.0 — 2026-10-22
- Templates can read the current render's
ctxin main markup, struct views and helper templates, without retaining a request on the component. Existing explicit context parameters andRender()methods remain compatible. The compiler usesui.Ctx, preserving HTML escaping and live frame trees (Render context). - Live components that read context are rendered again instead of reusing output solely because their props and Assigns are unchanged. Permission and identity refresh remains the auth layer's responsibility; handlers still authorize protected actions server-side.
- Regression coverage: per-user output, escaping, cancellation, implicit and explicit context, and context-dependent live updates in both HTML and tree protocols.
v1.3.0 — 2026-10-21
- Middleware in folder routes: a
middleware.godeclaringMiddleware—func(next http.Handler) http.Handler, orfunc(deps…) web.Middlewarewith its dependencies from the container — wraps every page, handler and endpoint below its folder, the root's outermost: headers, logging, rate limits, a short-circuited response. It runs before the guards and layouts load and sees the response on the way out; on a live page it wraps theGETand the socket's join, not the events (Middleware). A wrong signature is E0710;vuka routesprints a MIDDLEWARE column. vuka.RegisterType[T](attrs…)reaches stateless folder pages, method handlers and endpoints, as it already did live pages:vuka.RegisterType[Login](auth.Public())opens a stateless login page and itsPost(Attributes on a page type).- Example:
examples/folder-routesstamps and logs every request frompages/middleware.goand rate-limits its API frompages/api/middleware.go.
v1.2.0 — 2026-10-21
- Endpoints in folder routes: an exported type under
pages/withGet,Post,Put,PatchorDeletemethods and no markup answers those methods on its path, so a JSON API is folders like the pages (pages/api/employers/). AGET's struct parameter is its query string, the others' their body; a value answers JSON, an error its status, a nil error alone 204, aui.Nodea page, aweb.Redirecta redirect.pages/urlslinks to them andvuka routesmarks them(endpoint)(Endpoints). - Guards: a
guard.godeclaringtype Guard structwith aLoad(ctx, deps…) errorchecks every page, handler and endpoint below its folder and renders nothing — an API key, a permission. Guards and layouts load root-first, a folder's guard before its layout, and the first error answers the request, before the page mounts or a body is read. web addsweb.GuardOf[T]()(Guards). - A page or endpoint in
pages/with nothing to inject needs no constructor:vuka genwritesNew<T>for it. MountandChangedby name are a live page's hooks again, the simple form:func (p *T) Mount(ctx context.Context) error. Their signatures are checked and the browser can't call them;LiveSchemaand the constructor stay the way to unexported hooks and to field attributes (Hooks).- Example:
examples/folder-routeshas a JSON API underpages/apibehind a guard.
Changes
- On a stateless page the layouts'
Loadnow runs before the page'sMount(in 1.1 it ran after), so a guard or a layout protectsMounttoo. - An exported page-shaped type in
pages/is a route even without aNew<T>. A component the pages share belongs in another package (components/) or unexported; one that became a route shows invuka routes, and a path it takes from another page is E0701. MountandChangedfound by name no longer warn (W0303 is only forLoad<Group>now), andvuka fix hooksleaves them as they are.
v1.1.0 — 2026-10-21
- A live page's hooks in its constructor:
l.OnMount((*Login).mount),l.Loads("stats", (*Login).loadStats),l.OnChange(…)on itsui.Live, by method expression; a page whose only schema is its hooks needs noLiveSchemamethod (Hooks).vukavetchecks them (E0336, W0304, W0305). Additive:LiveSchemais unchanged. - Folder routes: the module's
pages/folders are the site's paths, each page type a route —Index,New,Edit…; a folder with aparams.gois a typed parameter (employer/is{employer}, aweb.Restfield{file...}, a segment that doesn't parse a 404); alayout.gowraps every page below it, composed parent to child, itsLoadfetching what it shows and guarding every page and handler beneath it;Post,Put,PatchandDeletemethods on a page answer on its path;Title()names the document (ui.PageTitle); anabout.vuka.htmlwith no Go type is a page of its own; a catch-all folder serves a client app's shell under its path, the pages beside it still winning.vuka genwrites theweb.Routescalls andpages/urls, a typed link to every page (urls.Employers.Employer(7).Edit.Path());vuka routesprints the table, and conflicts are errors at generation (E0701–E0709). web addsweb.Rest,web.PageRoute(),web.LayoutOf[T]()andweb.Receiver(ctor); a stateless page may have aMount. Example:examples/folder-routes(Folder routes).
v1.0.0 — 2026-10-20
The first release under the compatibility promise: vuka, ui, web, the vuka command and vukavet at v1.0.0, released with orm v1.0.0. From here on, an app that builds and passes its tests on v1.x keeps doing so on every later v1. The runtime is v1.0.0: generated code needs the vuka module at v1.0.0, and vuka fix runtime (which every upgrade runs) requires it.
go install github.com/vuka-lang/vuka/cmd/vuka@v1.0.0
vuka upgrade v1.0.0In an app written in Go, with the command and the analyzer as tools of the module:
go get github.com/vuka-lang/vuka@v1.0.0 github.com/vuka-lang/ui@v1.0.0 github.com/vuka-lang/web@v1.0.0 github.com/vuka-lang/orm@v1.0.0
go get -tool github.com/vuka-lang/vuka/cmd/vuka@v1.0.0 github.com/vuka-lang/vuka/cmd/vukavet@v1.0.0
go vet -vettool=$(go tool -n vukavet) ./... && go test ./...Plain Go is the language, .vuka the sugar
A vuka app can now be a normal Go module: .go files and .vuka.html templates, built with go build and run with go run ., with no vuka command at all. The orm, web (routes, live pages, islands, auth, deferred fields, validation) and ui behave the same as in a .vuka app, because a .vuka file compiles to exactly that Go (vuka as a library):
- Generated code uses the public API only and reads as hand-written Go: gofmt'd, one import block, real names (
areaCircle, notarea__Circle), doc comments carried over,//linedirectives only where the lines stop following the source, no absolute paths. vuka eject [-rm] [files | dir | dir/...]writes a.vukafile's Go beside it;-rmdeletes the.vukaand leaves plain source — its markup moved to.vuka.htmltemplates — that builds and behaves the same.- The generated speed-ups are optional. Without
orm generate's scanners the orm reads rows by reflection (1.05–1.07× end to end on SQLite), without render tracking a live component is diffed whole, and withoutvuka_calls_gen.govuka.Wrapcalls by reflection. One line opts back in://go:generate go tool vuka gen. - Each page has a Vuka / Go switch: the docs show every sample both ways, and the Go ones are type-checked against the libraries.
.vuka.html templates
Markup lives in template files beside the Go (or .vuka) it belongs to, compiled as the package's Go:
orders.vuka.htmlstarts with its package clause; the markup before its firstfuncline is theRenderofOrders(or theViewof a struct component, which is then itself aui.Node), its fields and methods by bare name;funclines start partials and function components.- Go statements start lines (
if,for,switch,x := …), holes are any Go, attributes takeclass:late={…},{attrs...},bind:valueandstyle:prop, and an event's call with no result is its handler (onClick={p.Cancel(o.ID)}). - Component tags are struct components (
<Card title="…">, attributes camelCase,<slot:footer>filling aNodefield), stateful components, and the package's partials and functions returningui.Node(<navLink item={i}/>,<layouts.NavLink …/>), every parameter butctx,childrenand slots required (E0144; an unknown tag is E0143 with a did-you-mean). A function component takingctxfirst is a tag too. - A template's
<script lang="ts">and<style scoped>are its component's, bundled and scoped by the vuka command;<script is:inline>takes{json(x)}. - In plain Go the same markup is
ui.HTML, its holes labelled with their Go and filled by the values after it; JSX in.vukafiles lowers to it. vuka run|build|test|vetcompile templates through the overlay,vuka genwritesx_html.gofor a plaingo build,vuka fmtformats them, andvuka lspserves them (below).
The ui kit is written this way: each component is a struct whose fields are its props, its markup a .vuka.html beside it — ui.Card{Title: "…"} is a Node, a <Card title="…"> tag in a template.
Registration in Go
Every decorator is a call a person can write, and the transpiler writes that call:
web.Routes, the registry every app takes atweb.New, andApp's methods of the same names:web.Routes.Get("/pets/{id}", ShowPet, web.Params("id", "store")),Live,Controller,Service,Handle. Options are typed values —web.Use(mw),web.Layout(l),web.Template(f), an auth gate such asauth.Required(),ui.Island(…)— and a gate on a route applies to its requests and its live page's events. Constructors areNewX.- Type decorators and declarers take
vuka.TypeFor[T](NewT)andvuka.DeclOf(fn); a call decorator isvuka.Wrap(fn, vuka.FuncInfo{…}, decorators…), with typed adapters invuka_calls_gen.goas a speed-up. - Overloads are named as Go names such functions:
areaCircle,AddIntInt, a live component'sUpdateNewMessage(ui.IsUpdatetakes it, and stillUpdate__Tfrom older commands). - Field references by address:
vuka.RefTo(func(p *Post) *string { return &p.Title }).
Schema, LiveSchema and typed fields
Attributes are values, given in one method per type:
- orm models:
func (p *Post) Schema(s *orm.Schema)withs.Model(orm.Meta{Table: "posts"})ands.Field(&p.Title, orm.Char{Max: 200});.vukaattributes lower to it. A pointer to no field, a nil attribute or a field behind a pointer is E0501–E0503. - Typed fields:
orm generatewritesPostFieldsbeside the model (post_gen.go) —PostFields.Author.Email.IEndsWith(…)through relations,PostPathfor paths — and number fields take arithmetic (PostFields.Views.Add(1)). In.vuka,Post.Titleis that field andPost.Objectsisorm.Objects[Post](), the model's manager. - Live pages:
func (p *Search) LiveSchema(l *ui.LiveSchema)withl.Field(&p.Q, ui.Bind{Debounce: 300 * time.Millisecond}, ui.URL("q")),l.Loads("lists", p.loadLists),l.OnChange(p.changed),l.Mount(p.mount). In.vuka:Q string @ui.Bind{…} @ui.URL("q")and@ui.Mounton an unexported method. Hooks may be unexported, so the browser can't call them; only exported methods without a hook arelive.*. Fields and hooks are checked at boot and by vukavet (E0335, E0336).ui.NoDebouncesends a bound field at once. - A routed live page owns its exported fields: what its handlers, hooks and bound fields set stays set across renders, a patch sets only the fields its URL binds, and a focused input takes a value the server changed (a form cleared once sent clears). An event's struct payload is checked against its
validate:tags, as a route's.
Islands for plain Go
ui.RegisterIsland[Chart]()finds its component as a bare@ui.Islanddoes; a route's option places a page backed by its island:app.Live("/board", NewBoard, ui.Island(ui.Layout(page))).go tool vuka build-islandsreads the registrations from Go source and builds the islands into the frontend's build (web/dist/.vuka/), withislands.d.tsandvuka-live.d.tstyped from the Go structs; a missing component is E0310 naming the call, a missing frontend E0609. Opt in with//go:generate go tool vuka build-islands.web.Dev()runs Tailwind, Vite andvuka build-islands -watchforVUKA_DEV=1 go run ., when they're installed, and does nothing in a production binary. Script islands (.ts) need no Node.
vukavet
go vet with vuka's checks, for apps in plain Go, with the codes the boot, the compiler and vuka vet use: routes (E0401 across imported packages, E0403, E0405, E0406, E0418, E0419, E0331), live and island pages (E0322–E0330, E0333, E0335, E0336), ui.HTML against its holes (E0127, E0128, E0132) and orm Schema methods (E0501–E0503). It is released with the set from v1.0.0 (cmd/vukavet/v1.0.0).
go get -tool github.com/vuka-lang/vuka/cmd/vukavet@v1.0.0
go vet -vettool=$(go tool -n vukavet) ./...Conformance
Every app of examples/conformance — library-users, crud, live, components, islands, islands-vue — exists as .vuka and as hand-written Go, and CI builds each five ways (vuka build; Go with and without the generated speed-ups; ejected, with and without them) and requires the same HTTP responses, live replies, SQL and generated files from each. A difference is a bug.
Editor
vuka lspserves.vuka.html: diagnostics in the template's own positions, hover, definition and completion of the Go in holes and statement lines as in a Go file of its package (the component's fields and methods first), of tags and their parameters, and semantic tokens. A template with a syntax error leaves the rest of its package checked.- The VS Code extension, 0.5.0 (its own version), highlights
.vuka.htmlandui.HTMLmarkup, and is published to Open VSX. Zed reads templates as HTML, coloured fromvuka lsp.
Breaking changes since v0.50.0
vuka upgrade v1.0.0 moves vuka, ui and web to v1.0.0, and the orm to v1.0.0 when the app requires it; then it runs these vuka fix fixers, then vuka vet ./... and vuka test ./.... The go.mod and go.sum it started from are kept in .vuka/upgrade/.
| Fixer | What it rewrites | Runs |
|---|---|---|
runtime | requires the vuka runtime v1.0.0 | every upgrade |
templates-package | starts each .vuka.html with its directory's package clause (a missing one is now E0142) | every upgrade |
db-schema | orm.Schema{…} (the names-set struct) → orm.DBSchema{…}; orm.Schema is now a model's Schema method's | every upgrade |
attributes | a live page's bind:, url:, defer:, validate: tags and a model's orm: tags → @ui.Bind, @ui.URL, @ui.Defer, @validate.…, @orm.Column(…), … (the tags still work, with W0302) | v1.0.0 |
hooks | Mount, Changed, Load<Group> found by name → @ui.Mount, @ui.OnChange, @ui.Loads("group") (still found, with W0303) | v1.0.0 |
ui-structs | ui.Card(ui.CardProps{…}) → ui.Card{…}, ui.Table(ui.TableProps[T]{…}) → ui.Table[T]{…}, in .go and .vuka | v1.0.0 |
queries | queries made for orm.Query: vuka.Or of fields → orm.Or, package fn → the orm's (fn.Lower → orm.Lower, fn.In → InQuery), a First read as an Option → orm.Optional(….First(ctx)), Post.Objects.Manager() → Post.Objects | v1.0.0 |
The other fixers (static-names, orphans, attr-of, ui) are unchanged; vuka fix -n lists what any of them would do.
What vuka fix can't do, and what to do instead:
Post.Objectsis the model's manager. In.vuka, a model'sObjectswas anorm.Query, whose terminals returnedResults; it is noworm.Objects[Post](), whose terminals return(T, error). With?nothing changes. Code calling aResult's methods on a terminal uses?or the value and error instead.Updatetakes anorm.Set, andGetOrCreate/UpdateOrCreatetake a lookup and defaults:diff- Post.Objects.Filter(Post.ID.Eq(id)).Update(ctx, orm.Assign(Post.Views, n))? + Post.Objects.Filter(Post.ID.Eq(id)).Update(ctx, orm.Set{Post.Views.Name(): n})? - out := Session.Objects.UpdateOrCreate(ctx, s, Session.Key)? + s, created, err := Session.Objects.UpdateOrCreate(ctx, orm.Q{Session.Key.Name(): key}, orm.Defaults{…})Go code naming an overload by its generated name uses the new one:
area__CircleisareaCircle.@exportnames are unchanged.Go code that called
ui.Bind(init, expr, deps…)(a state binding, what older commands generated) callsui.BindExpr;ui.Bindis the attributeui.Bind{Debounce: …}.Committed generated code (
vuka gen -inplace) is regenerated withvuka gen -inplace; forms older commands wrote (vuka.TypeWith,vuka.FuncDecl,vuka.NewCall,vuka.RefOfwith index paths,Base_Objects) are deprecated or gone.
Deprecated, and still working through v1: the struct tags and named hooks above (vuka vet warns, W0302 and W0303), and, marked // Deprecated: with their replacement, the kit's XProps types (aliases of the structs), orm.Query and package fn, Meta() and SetFieldOptions on models, vuka.TypeWith, TypeOf, FuncDecl, MethodDecl, DeclareWith, DecorateType, vuka.Func and NewCall, and RefOf with index paths.
ORM v1.0.0
orm v1.0.0 is released with the set, requires vuka and web v1.0.0, and makes the same promise. Since v0.9.1:
Schemamethod and typed fields, above:func (p *Post) Schema(s *orm.Schema),PostFieldsbeside the model,PostPaththrough relations.Model[T]is what a Go model embeds (orm.Basein.vukais writtenorm.Model[T]);orm.Objects[T]()is its manager andorm.For[T]()registers it.- The names-set struct is
orm.DBSchema(orm.Of[T](orm.DBSchema{…}),DBSchema.Verify);vuka fix db-schemarenames it. - Terminals return
(T, error)—All,First,Get,Count,Exists,Update,Delete;orm.Optional(qs.First(ctx))turnsErrNotFoundintoNone.Updatetakesorm.Set{column: value};GetOrCreateandUpdateOrCreatetakeorm.Qandorm.Defaultsand return the row and whether it was created. NumberFieldand arithmetic:orm.Set{"views": PostFields.Views.Add(1)}, in conditions too;SaveFieldstakes typed fields, Go names or columns.orm.Transaction(ctx, fn, opts…), also as an around decorator in.vuka(@orm.Transaction,@orm.TxOn("crm")).- Reflection fallback: a model without generated scanners works, by reflection (
ORM_REFLECT=1runs the suite that way);orm generate --missingreports what is out of date, for a build tool's overlay. - Option fields get generated scanners, typed fields work in
orm.LowerandQvalues, andModelConfig.Fieldsskips fields per model at run time.orm.Queryand packagefnare deprecated.
New apps from vuka new require orm v1.0.0. The orm needs Go 1.27.
v0.50.0 — 2026-10-19
The first set: vuka, ui, web and cmd/vuka at v0.50.0. Runtime unchanged, v0.16.0 (the vuka module v0.50.0 satisfies it). New apps use orm v0.9.1.
go install github.com/vuka-lang/vuka/cmd/vuka@v0.50.0
vuka upgrade v0.50.0
go get github.com/vuka-lang/orm@v0.9.1One version for the toolchain
- A release is a set. vuka, ui, web and the
vukacommand are tagged together at v0.50.0. An app requires the three libraries at one version and uses the command of that version;vuka newwrites a go.mod pinned to its own set. The ORM keeps versions of its own. vuka versionprints the command's set and, inside an app, the versions its go.mod requires, warning when they aren't one set (after ago getof one module alone, say).vuka upgrade [version]moves an app to a set, the latest by default:go getof vuka, ui and web (nevergo mod tidy), thevuka fixrewrites registered for the releases in between, thenvuka vet ./...andvuka test ./..., with a summary.-nonly says what it would do. The go.mod and go.sum it started from are kept in.vuka/upgrade/; to undo an upgrade, move them back.- A release train and a compatibility promise. Fixes ship as a weekly patch release, security fixes at once, features in minor releases with upgrade notes; breaking changes are deprecated first and come with a
vuka fixrewrite. See Versions and compatibility.
Diagnostics with codes
- Every error has a code. Errors of the compiler,
vuka vet, the editor and the libraries' checks at boot carry a stable code (E0203;W0301for a warning), a place, a code frame on the terminal (coloured on a TTY, plain underNO_COLOR) and ahelp:line with the fix, with a did-you-mean where one fits. vuka explain <code>prints the code's page of the catalogue: what it means, and an example before and after.-diag=jsonprints diagnostics as JSON, for scripts and tools.- The editor shows each diagnostic's code, linked to its page, and its help.
- More is caught before boot.
vuka vetand the editor now report from the source what used to fail only when the app started: an island component that isn't found or is ambiguous (E0310, E0311), two islands of one name (E0312), bad@ui.Islandarguments (E0320), and on pages backed by a component a badbind:,defer:orvalidate:tag (E0322, E0323, E0328), a deferred group without its loader (E0324), a loader of the wrong shape (E0325) and two handles of one name (E0326); W0301 warns about a live page routed with@web.Get. Toolchain problems are coded too: Node, packages, the Vite plugin and TypeScript 7 (E0602–E0608). - Boot errors of ui and web are diagnostics, placed at the declaration they are about — a route declared twice names both declarations (E0401). In Go,
diag.Of(err)gives the code.
What to do: a test matching an error's whole text may need the new form (error[E0401]: GET /pets is declared twice …). Match the code instead.
Fixes
vuka run -watchon Linux no longer restarts the app on every save. It compared whole binaries there, which differ on any change; it now reads the Go build ID, so a save that leaves the program as it was (a comment, a test file) keeps the app running, as on macOS.- Live pages: a broadcast right after joining is no longer lost. A page's topics are now subscribed before its join's (or event's, or navigation's) reply is sent, so a broadcast the client causes as soon as it has the reply reaches it.
- Dev assets: generated asset files are written through a rename, so a page loading while an island is rebuilt no longer reads half a file or the previous manifest.
- The compiler and
vuka fmtno longer fail on the inputs fuzzing found: a file with a decorator or an enum's import and no package clause, a truncated or emptymatchcase, an empty receiver list, a positional struct pattern, a positionalui.Classliteral, an empty composed decorator. The formatter runs to a fixed point, so formatting a formatted file changes nothing.
Island ids changed
An island host's data-vk-s is now the island's place among its file's components instead of a byte offset into the file: pets.vuka#865 becomes pets.vuka#3. Reformatting a file no longer changes it. Apps don't read it, but a test or script that does — a selector like [data-vk-s="pets.vuka#865"], a snapshot or golden of rendered HTML — needs the new value: run the page and copy it, or select the island another way (its component's own markup, an id or a data-testid you give it).
ORM v0.9.1
Go 1.27.2 writes compiled packages in a format the ORM's tools (orm v0.9.0 and older) can't read. They then saw no models: go tool orm makemigrations planned to drop every model, and pages using the ORM returned 500. orm v0.9.1 reads the new format, and its tools now stop with an error naming the cause when they can't read a package, instead of seeing no models. Apps building with Go 1.27.2 or newer should move to it:
go get github.com/vuka-lang/orm@v0.9.1New apps from vuka new require it.
Tests
The libraries' and the command's suites run on every push: vet, race tests, the end-to-end suites with Vite and Chrome, and the fuzzers. A test whose tool (Node, Chrome, Tailwind) is missing fails under CI instead of skipping.
cmd/vuka v0.45.3, web v0.36.3 — 2026-10-16
Runtime unchanged, v0.16.0. New apps use web v0.36.3.
- Moving between pages backed by Vue components with popovers, modals or selects no longer crashes the next island. A navigation morphs the body into the new page's, and removed what a component had teleported to the body — Nuxt UI's (reka-ui's) portals and their empty anchors, which every row's popover keeps there even closed. Unmounting the old app then walked a teleported fragment whose anchors were gone and failed, the failure was swallowed, and the next island's mount on that host patched against the old app's tree: "There is already an app instance mounted on the host container", then
can't access property "nextSibling", e is null. The morph now leaves the nodes the page's scripts put in the body where they are (web), and the Vue adapter forgets an app whose unmount fails, logging why, so the next mount starts clean.
cmd/vuka v0.45.2, web v0.36.2 — 2026-10-16
Runtime unchanged, v0.16.0. New apps use web v0.36.2.
- Lazy components in Vite islands load. An island built with Vite is built with a relative base, so a dynamic import — a
defineAsyncComponent(() => import('./Modal.vue')), a UI library's lazily loaded component — fetches its chunks and stylesheets beside the chunk importing it, under/_vuka/i/. Before, Vite's preload helper asked for them at the site's root (/chunk.*.js), where the app answers 404, and the lazy component never rendered. Abaseinvite.configno longer matters to the island build; drop one set to work around this. - One island per host. Moving between pages backed by components, and a rebuild under
vuka runwhile a page was open, could mount a second app on an island's host (Vue: "There is already an app instance mounted on the host container", then anextSiblingerror): a host whose island wasn't built yet was remembered after another island mounted on it, and the next build mounted that island again. The loader now unmounts what a host has before mounting on it, and forgets such a host once an island mounts. The Vue adapter unmounts an app left on its host, too. - An island that fails to load says so. A module that doesn't load, or a mount that throws, marks the host
data-vk-error="failed"and, undervuka run, shows why on the page; a build bringing another module for it mounts it.
cmd/vuka v0.45.1 — 2026-10-16
Runtime unchanged, v0.16.0.
vuka runrebuilds the islands for every file their build reads. A Vite (or Node) island build is redone when anything under the frontend root changes —vite.config, theapp.cssentry, a shared component an island imports, an island in a subfolder,_setup,package.json, the lockfile — and when a file under a directoryapp.cssnames with@sourcedoes; before, only the island's own file was watched.node_modules,dist, hidden paths,.d.tsfiles (vuka's and those Vite plugins write) and Go sources are left out, so a build doesn't start another. A vanilla island is rebuilt when a file it imports changes.- The island cache keeps up. A build is cached under what it saw before it ran, so an edit made while Vite builds is built next time, and a component outside the frontend root is keyed with its directory.
cmd/vuka v0.45.0, web v0.36.0, ui v0.30.0 — 2026-10-16
Runtime unchanged, v0.16.0. New apps use ui v0.30.0 and web v0.36.0.
- Deferred fields. A field of a page backed by a component tagged
defer:""isn't in the first render: its group's loader,Load<Group>(ctx) error, runs after it and the field reaches the component as an update — a slow count or a list no longer holds up the page, with no code in the component.defer:"lists"groups fields under one loader (LoadLists); a baredefer:""is the field's own group. On a live page the groups load concurrently once the page joins, each sent as it finishes, their context ending with the page; on a stateless page the component posts one signed, gated load once it mounts. A loader runs on a copy of the page and only its group's fields are kept.live.stats.valueisundefinedandlive.stats.pendingtrue until then; a failed loader islive.stats.error, the page carrying on.vuka-live.d.tstypes the field optional and its handleLiveDeferred<T>; loaders aren't onlive, and hover on one names its fields. Deferred fields. Changed(ctx, changed ui.Changed)says which bound fields an update set:changed.Has("status")(wire name, handle or Go name) andchanged.Names()(wire names, sorted).Changed()andChanged(ctx)still work. Which fields changed.
cmd/vuka v0.44.0, web v0.35.0, ui v0.29.0, vuka v0.32.0 — 2026-10-16
Runtime unchanged, v0.16.0. New apps use ui v0.29.0 and web v0.35.0; the command requires vuka v0.32.0.
@web.Liveon a page backed by a component. An@ui.Islandstruct embeddingui.Liveis routed with@web.Live("/path"), its options (web.Layout, the type's gates) as for any live page.@web.Getstays the stateless form;@web.Getwithui.Livestill serves a live page, andvuka vetand the editor suggest@web.Livefor it. Pages backed by a component.- Layouts in the decorator.
@ui.Island(ui.Layout(layouts.Page("Orders")))is the layout of the page the type backs: afunc(ui.Node) ui.Node, or afunc(ctx, ui.Node) ui.Nodereading the request (the user, the path,ui.PageTitle(ctx)); several nest, the first outermost. It wins over the route'sweb.Layout, thenweb.LiveLayout, then a bare document, and applies only where the type is routed as a page. ATitle() stringmethod titles the page: the bare document's<title>,ui.PageTitle, and a document without one. Pages sharing a layout keep its elements across live navigation. Layouts. ui.Strategy("load")sets an island's default strategy:@ui.Island(ui.Strategy("load"))keeps the inferred path. ui v0.29.0'sIslandtakes...any: a path, a strategy, then options.vuka add page --islandwrites@web.Livefor a live page (@web.Getwith--stateless) and@ui.Island(ui.Layout(layouts.Page("Title")))when the app haslayouts/;--layout exprnames another layout,--layout noneleaves it out.- vuka v0.32.0: the compiler finds the type an
@ui.Islanddecorates past any argument expression — nested calls, strings with parentheses, over several lines — so a live island page with options still gets its Render. The vuka command reads the literal path and strategy and skips the other options; hover on a decorator withui.Layoutsays where the layout applies.
cmd/vuka v0.43.0, web v0.34.0, ui v0.28.2 — 2026-10-16
Runtime unchanged, v0.16.0. New apps use ui v0.28.2 and web v0.34.0.
- Islands move the page.
live.navigate(href, opts?)andlive.patch(href, opts?)onuseLive(), andnavigate/patchonuseVuka()in any island, do what adata-vk-linkclick does: over the live connection when the page is joined (gates, a patch'sUpdate, the address, scroll, focus,vk:navigate), else a page load.{ replace: true }replaces the history entry. The promise resolves with{url, patch}once applied, and rejects for a URL that isn'thttporhttpsor when another move takes its place.window.vuka.navigate(href, {patch, replace})is the same call for any script. From an island. <VukaLink>invuka:livefor Vue, React and Svelte: an<a href>markeddata-vk-link(patch,replace), withactiveClass(defaultactive,exactfor the same path) andaria-current="page", typed invuka-live.d.tsfor the frameworks the islands use. A link withdata-vk-replacereplaces the history entry.- web v0.34.0: a navigation that morphs an island's host into another island's (another name, or another live instance) unmounts the old one and mounts the new one; before, the old component stayed.
- ui v0.28.2: a patch of a page backed by its island runs its
Updatetakingweb.URLParams; before, the page stayed as it was.
cmd/vuka v0.42.1, web v0.33.0, ui v0.28.1 — 2026-10-16
Runtime unchanged, v0.16.0. New apps use ui v0.28.1 and web v0.33.0.
- Breaking: a route's bound struct is validated with the islands' rules. After a handler's struct parameter is bound — JSON body, form, multipart, query string or path segments — its
validate:tags are checked, nested structs and slices of them included:required,omitempty,min,max,len,oneof,email. Before, onlyrequiredwas checked and other rules were ignored. A failure answers 422 (it was 400name is required) with every failing field's message:{"error": "invalid: email: required", "fields": {"email": "required"}, "status": 422}— keys are the field's path by json names for a JSON body (address.city,items.1.city), by form names otherwise; an HTML route answers its 422 error page. Clients that matched 400 or the"x is required"text should read status 422 andfields. A rule web didn't check before (a typo,min=x) now failsBuildnaming the route, and a rule it ignored now applies. The error is aweb.Invalid, soweb.OnErrorreads its fields witherrors.As. Any JSON error from aweb.Invalidnow carriesfieldstoo. Validation. - ui v0.28.1:
ui.ValidateTags(v, "form", "json")validates naming fields by the first tag they carry.
cmd/vuka v0.42.0, web v0.32.0, ui v0.28.0 — 2026-10-16
Runtime unchanged, v0.16.0. New apps use ui v0.28.0 and web v0.32.0.
- Pages backed by a component check
validate:tags. Abind:field's tag (Q string `bind:"q" validate:"max=50"`) is checked when the component sets it, every field of one set before any is applied, and a method's struct arguments are checked, with the structs they hold at any depth, before it runs. A failure applies nothing, runs neitherChangednor the method, and answers 422 with each field's message —{"status": 422, "message": "invalid: q: at most 50 characters", "fields": {"q": "at most 50 characters"}}; a method argument's fields by their path inside it (years,level.code,items.0.code) — live and stateless alike. Rules:required,omitempty,min,max,len,oneof,email; another rule, or a bad value, stops the app at start (ui v0.28.0'sui.Validateandui.CheckValidate). Islands. live.q.error. A bound field's handle has the server's message for it, ornull; what was typed stays in the input, shown with its error, until the field is set again or a method succeeds. A failed call's promise rejects with anErrorcarryingstatusandfields.vuka-live.d.tstypes it:LiveBound<V>hasreadonly error: string | null.
cmd/vuka v0.41.0, ui v0.27.0, vuka v0.31.0 — 2026-10-16
Runtime unchanged, v0.16.0. New apps use ui v0.27.0; the command requires vuka v0.31.0.
@ui.Islandfinds its component. Written bare,@ui.IslandonOrdersisislands/Orders.<ext>under the frontend root — in the module's folder for a package undermodules/<m>/(web/islands/sales/Orders.vue) — the extension whichever of.vue,.tsx,.jsx,.svelte,.ts,.jsexists. None, or two, is an error naming them.@ui.Island("", "load")keeps the inference and sets the default strategy;@ui.Island("charts/Revenue.vue")works as before. Islands. ui v0.27.0'sIslandtakes its arguments as...string.- Generated code infers.
vuka add page --island, andvuka new's sample island, write a bare@ui.Island; with--direlsewhere the path is written. - The editor knows islands. Hover on
@ui.Islandshows the component file (inferred or written, relative to the module root) and its framework, go to definition opens it, and a missing or ambiguous file is a diagnostic on the decorator without a build. Hover on a page'sMountorChangedsays it is a hook the server runs, not callable fromlive. - Fixed: a method's parameter types in
vuka-live.d.ts. A type used only by a page's method (Chasing(ctx, name string, data Data)) was named but never declared, solive.chasing(…)didn't type-check. Every struct a field or a parameter reaches is declared now, at any depth: another package of the module's (shared.Level), in slices, maps and pointers, recursive ones by name, embedded structs' fields promoted asencoding/jsondoes (json names,omitemptyand pointers optional), and generic ones as generic interfaces (Page<Tag>).
cmd/vuka v0.40.1, web v0.31.2 — 2026-10-16
Runtime unchanged, v0.16.0. New apps use web v0.31.2.
A page whose component has fields but no methods has
live. A page backed by a component withbind:and read-only fields and onlyMountandChangedgave the componentuseLive()asnull, so readinglive.titlefailed in the browser. Every page backed by a component now gets its handles, live and stateless alike (web v0.31.2; no change to your code or to ui).An island build that fails shows in the browser. Under
vuka run(and-watch) a failed build of the islands — a Vite build of a.vuecomponent that doesn't compile, say — used to reach the terminal only, while the page went on with the last good bundle. The development toolbar now saysisland build failed(asset build failedfor styles and scripts) with the build's error in its drawer, the end of what Vite said included, colours stripped; it clears when a later build succeeds.An island the bundle doesn't have says so in its place. In development,
<Levels … />whose component isn't in the last good bundle renders a box — "Island Levels isn't built", and that the island build failed when it did — instead of nothing, and mounts once a build has it, without a reload. In production nothing changes: no box, andvuka buildstops on an island that doesn't build.The last good bundle keeps serving meanwhile: the other islands work.
cmd/vuka v0.40.0, web v0.31.0, ui v0.26.0 — 2026-10-16
Runtime unchanged, v0.16.0. New apps use ui v0.26.0, web v0.31.0.
- A page's component reads and sets its fields through
live. In a page backed by a component, every exported field is a handle onuseLive():live.rows.value(orget()) reads it and follows the server. A field taggedbind:"q"is one the component sets —live.q.set(v), orv-model="live.q.value"— and the value is the browser's at once while the set waits for a pause in typing (300ms;bind:"q,debounce=500",set(v, { now: true })). Sets of several fields within one pause go as one update; the server sets the fields, runs the type'sChangedand answers with the props — over the connection on a live page, as the signed round trip on a stateless one. A field withoutbind:is read only: nosetin the types, and the server refuses a set of it (403). See Pages backed by a component. - Each method has its own
pendinganderror(live.cancel.pending), beside the page'slive.pendingandlive.error. Calls and sets go one at a time, in order; a method sends the sets waiting first. - A method and a field of one name on
live, or abind:tag that doesn't fit, stop the app at start with what to rename.Changedisn't callable. - Components reading their props with
defineProps<T>()(React: props, Svelte:$props()) and callinglive.method(…)work as before. vuka-live.d.tstypes the handles (LiveBound<V>,LiveField<V>) and each method's state.vuka add page --islandwrites a page whose search field isbind:with aChanged, and a component setting it throughlive(v-model="live.q.value", Reactvalue/onChange, Sveltebind:value). With--module mthe component goes inweb/islands/m/, asvuka add island --module mdoes.
cmd/vuka v0.39.3 — 2026-10-16
Runtime unchanged, v0.16.0.
- A Vue page backed by a component builds when TypeScript 7 is about. Vue's compiler reads
defineProps<T>()of a type imported fromvuka:livethrough TypeScript's JavaScript API, which TypeScript 7 doesn't have; a UI library depending ontypescriptcould hoist 7 into the frontend, and the island build failed, leaving the page blank.vuka add island/page --islandnow pintypescript~6.0.3beside Vue when the frontend has none, and the build's error says what to run. - Editors find
vuka:live. A frontend without atsconfig.jsongets one (mappingvuka:livetovuka-live.d.ts) fromvuka add islandand from the build that writesvuka-live.d.ts. @ui.Islandpaths from the frontend root. A path that doesn't start with.and isn't beside the declaring file is found from the frontend rootweb.FrontendRootnames:@ui.Island("islands/Orders.vue")from any package, instead of"../../web/islands/Orders.vue". A path beside the file, or starting with./or../, reads as before.vuka add pagemakes a live page by default (@web.Live, orui.Livein a page backed by a component);--statelessmakes the@web.Getone. A path with{parameters}stays stateless unless--live.- The Vue component
vuka add page --islandwrites binds its search box withv-modeland calls the method from awatch. vuka add islandpicks the framework the frontend already uses; the help now says the flags are for adding one in another.
cmd/vuka v0.39.2 — 2026-10-16
Runtime unchanged, v0.16.0.
vuka add islandwrites the.vukaside too. Besides the component underweb/islands/, it writes a component placing it —components/chart.vukawithChart(ChartProps)— so a page writes<components.Chart Title="Sales" Count={3} />instead of importing the file itself.--module mputs both in the module:modules/m/chart.vukaandweb/islands/m/Chart.vue.--modulefor services and entities, and the app's own folders.vuka add service Mailer --module notesandvuka add entity Comment --module postsname the module as the other kinds do (notes/Mailerstill works); without a module they go inservices/andentities/.vuka add entity --unmanagedmaps an existing table:@orm.Meta{Table: "…", Unmanaged: true}, no timestamps, test or migration, and the app needs nomigrations/. (In zsh, quote an optional field:'code:string?'.)
web v0.30.1 — 2026-10-16
Security fix. Runtime unchanged, v0.16.0; ui unchanged, v0.25.0. The vuka command is cmd/vuka/v0.39.1. New apps use web v0.30.1.
- A stateless page's signed props are the visitor's. A page backed by a component without
ui.Livesends its props to the browser signed, and each call carries them back. The signature bound the page's path and an expiry but not who the page was rendered for, so anyone holding a page's props could replay them — as another user, or signed out — until they expired (calls still passed the page's gates). The signature now also binds the visitor's sign-in (withweb/auth: the user and the session, token or JWT they signed in with; no one, for an anonymous visitor) and the page's type. Props replayed by another visitor, anonymously, after a sign-out and in again, or at another page answer like a forged signature (403). Pages already open when the app is upgraded are refused once and work again after a reload. No change to apps or components:go get github.com/vuka-lang/web@v0.30.1. web.LiveIdentitykeys a sign-in, not only a user: live adoption, too, only adopts a page for the sign-in that rendered it.
v0.30.0 — 2026-10-16
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.39.0. New apps use ui v0.25.0, web v0.30.0.
- Import a component as an island.
import Week "./web/islands/Week.vue"in a.vukafile makes<Week …/>a tag: the compiler reads the props from the component's TypeScript — Vue'sdefineProps/defineModel/defineEmits, a React component's typed props, Svelte's$props(), a vanillamount(el, props)— and type-checks every attribute against them, with no Go type to write and no Node to run.<ui.Island>is needed only for a fallback. React (.tsx/.jsx) and Svelte islands build beside Vue.vuka lspcompletes the props. - Island props both ways. On a live page every prop follows the server (
oncekeeps the first value). A function prop takes a method of the page — the component calls it, the method runs on the server — or JS commands. Aui.Statepassed as a prop is shared: the component writes it back throughdefineModel, a ReactsetXprop or a Svelte$bindable, and every binding on the page follows. - Pages backed by a component.
@web.Geton an@ui.Islandtype serves the component as the page: exported fields are its props (url:"q"fields kept in the address), exported methods what it calls withuseLive<T>()fromvuka:live, typed from the Go struct invuka-live.d.ts. Embeddingui.Livemakes it a live page; without it a call is a POST carrying the page's signed props back, so the page needs no connection. Errors arrive aslive.error(web.Invalidfor fields), aweb.Redirectnavigates, and the type's gates (@auth.Required) hold for calls as for the page. Every island knows the signed-in visitor (useVuka()). See Pages backed by a component. - Client state. A write (
open.Set(false)), aui.Nodeor an attribute list built from states and passed as a prop or child is passed as it is, not read as a state.ui.BindAttr(name, s)binds a state into a Go attribute list. Anautopopover the browser closes (Escape, a click outside) writes itswhenstate back, and<ui.Show>without a transition hides at once, so swapped panels never show together. vuka addmakes the pieces of an app:service,component,island(Vue, React or Svelte, with its packages installed),page(--live,--island) andentity(an orm model with its migration).--dry-runlists what it would write;--forceoverwrites. See add.- Long steps say they are going. A package install, the Vite island build and
vuka new's module fetch show a spinner on a terminal and a heartbeat line elsewhere; a failure prints the tool's last lines. - Faster rebuilds. What a package was transpiled to, and the API it was checked against, is kept on disk (the user's cache directory,
vuka/transpile):vuka build,run,test,vetandgentranspile only the packages whose inputs changed, andrun -watchstarts from that. The Vite island build is skipped when nothing it reads changed.VUKA_CACHE=offturns both off.vuka runleaves the filesweb.Frontendserves out of the binary (they are read from disk in development), so the linker doesn't copy them on every rebuild;-embedorVUKA_EMBED_STUB=offbuilds them in.
Upgrading. web.Get, Post, Put, Patch, Delete and Handle now return a vuka.Bundle (made with the new vuka.Dual: a route on a function, a page on a type) rather than a func(*vuka.Decl). @web.Get(…) in a .vuka file is unchanged. Go code that used the result as a function changes:
// before: web.Get("/pets")(d)
vuka.DeclareWith(web.Get("/pets"), d) // now// before: func ApiRoute(p string) func(*vuka.Decl) { return web.Get(p) }
func ApiRoute(p string) vuka.Bundle { return web.Get(p) } // nowA composed decorator (decorator ApiRoute(p string) = @web.Get(p) …) needs no change. web v0.30.0 requires vuka v0.30.0: go get github.com/vuka-lang/web@v0.30.0 brings it along.
v0.29.0 — 2026-10-15
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.38.1. New apps use ui v0.24.0, web v0.29.0.
- Client state.
ui.State(v)declares a value the browser keeps — a menu'sopen, the picked tab, a filter. Commands change it with no round trip (open.Toggle(),tab.Set("env"),n.Inc()), and the attributes, text and classes that read it follow, written as plain Go expressions:<ul hidden={!open}>.ui.Derived(expr)names a value built from states,ui.Classtoggles classes,<ui.Show when={open}>shows and hides with transitions, and a struct state's fields are read one by one. The server renders the initial values, so the HTML is right before any script runs; an expression that can't run in the browser is a compile error naming what to compute on the server. See Client state. vuka lsp: type-aware highlighting (semantic tokens) in cmd/vuka v0.37.0, and no flicker of stale diagnostics while typing in v0.36.0. cmd/vuka v0.38.1 reports its own version correctly.
v0.27.0 — 2026-10-13
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.32.0. New apps use ui v0.21.0, web v0.24.0.
- UI islands (Phase 3 — the live bridge). Islands are now reactive both ways. Server → island: a
*ui.Assign[T]island prop serializes its value, and a live re-render pushes the changed value to the mounted component'supdate()with no remount (the live-view morph updates an island host's attributes but leaves its client-owned DOM). Island → server:on<Emit>attributes on the tag bind the component's emits to live-view handlers —<DataTable rows={live(d.rows)} onRowClick={d.RowClick}/>lowers the handler to a registered id (like an elementonClick, noAllowPush), and the client adapter forwards the Vue emit to it; the emit's argument arrives as JSON bound into the handler's struct parameter (ui.Event.Data). Verified end to end: an island emit runs a server handler that bumps a live prop, which updates the island in place.
v0.28.0 — 2026-10-13
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.34.0. New apps use ui v0.22.0, web v0.25.0.
- Stable island
data-vk-s. A<ui.Island>now lowers toui.MountIsland("<site>", …)with a stable per-placement id (the file + the wrapper's source offset), used as the host'sdata-vk-s. Previously the host got a per-render counter, so every island re-render churneddata-vk-sin the live-view diff (spurious patch weight) and brokectx.refafter an update (the captured scope no longer matched). The id is now identical across renders. Requires ui v0.22.0 (MountIslandgained the leadingsiteparameter).
cmd/vuka v0.35.0 — 2026-10-13
Runtime unchanged (vuka v0.28.0); a command-only release.
vuka lsp: auto-imports consolidate into one block. Accepting a completion (or a decorator / static accessor) that needs an import now folds it into a single sortedimport ( … )block — folding any existing loneimport "x"lines in too — instead of appending another loneimportline each time. (addImportsnow returns a set of edits rather than one insertion.)
cmd/vuka v0.33.0 — 2026-10-13
Runtime unchanged (vuka v0.26.0); new apps use ui v0.21.0, web v0.25.0.
- Vite island build (for Nuxt UI and other Vite-plugin UI libraries). When a framework island's frontend root is a Vite project (has a
vite.config.*), the vuka command builds the.vueislands by running the project's Vite (with its[vue(), ui(), tailwindcss(), vuka()]plugins) instead of the Node-esbuild path — so Nuxt UI's components auto-resolve and its Tailwind v4 CSS is produced. vuka reads Vite's manifest, serves the island + adapter + shared chunks at/_vuka/i/, and injects the island CSS (<link>on first hydration). A frontend root without avite.configkeeps the esbuild path; vanilla.tsislands always use esbuild. Needs web v0.25.0 (its Vite plugin gains the island-build mode + island-CSS serving). vuka new --islandsnow scaffolds a Vite + Nuxt UI frontend root by default:vite.config.mts([vue(), ui(), tailwindcss(), vuka()]), the dep set (vite, @vitejs/plugin-vue, @nuxt/ui, @tailwindcss/vite, tailwindcss, vue, vue-router),app.css(@import "tailwindcss"; @import "@nuxt/ui";), and a sample island using a Nuxt UI<UButton>.- Dev (
vuka run) rebuilds Vite islands on change (a full island build, not yet HMR off the Vite dev server — a follow-up).
cmd/vuka v0.31.0 — 2026-10-13
Runtime unchanged (vuka v0.26.0); a command-only release.
vuka new --islands. Scaffolds a sample Vue island wired end to end: aweb/frontend root (package.jsonwith esbuild + esbuild-plugin-vue3 + vue, aweb/dist/index.htmlstub,web/islands/Counter.vue), an@ui.IslandGo type, a live page placing<ui.Island><Counter … client:visible/></ui.Island>, andweb.Frontend(dist, "web/dist", web.FrontendRoot("web"))in main. Offered for--ui=live --frontend=none(refused otherwise, with a clear message); default off, so every existingvuka newcombination is byte-for-byte unchanged. After scaffolding, runcd web && npm installonce;vuka buildthen bundles the island on every build.
cmd/vuka v0.30.0 — 2026-10-13
Runtime unchanged (vuka v0.26.0); a command-only release.
- UI islands (Phase 2 — Vue).
@ui.Island("…/X.vue")now builds: the vuka command compiles the SFC with Node esbuild +esbuild-plugin-vue3(one code-split build per app — the Vue adapter and every.vueisland as entry points, with the Vue runtime deduped into a shared chunk), serves the chunks at/_vuka/i/, and records each island with its module + a Vue adapter chunk; the client loader mounts it withcreateApp, re-pushing changed props on a live re-render and unmounting when it leaves. The build deps (vue,esbuild,esbuild-plugin-vue3) come from the frontend root (web.FrontendRoot); a server-rendered app without a frontend adds a minimalpackage.jsonthere. An optional_setup.ts(default export(app)=>{}) runs per island app. Vanilla islands are unchanged; React/Svelte await a later phase. Design: docs/design/islands.md.
v0.26.0 — 2026-10-13
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.29.0. New apps use ui v0.19.0, web v0.22.0.
- UI islands (Phase 1 — vanilla). Astro-style client islands: a server-rendered page stays zero-JS, and a component becomes an interactive island hydrated on a
client:*strategy. A<ui.Island>wrapper around an island-component tag lowers to aui.MountIsland(...)call — the body's attributes become the island's props,client:load/idle/visible/media/onlythe hydration strategy, its children the slot, and a nested<ui.Template fallback>the fallback shown until hydration. An island is a Go struct annotated@ui.Island("islands/Counter.ts")(Go owns the props); the vuka command bundles the component into a lazy chunk served at/_vuka/i/, records it in the asset manifest, and generatesislands.d.tsfrom the struct into the frontend root (web.FrontendRoot). The client loader arms the strategy (IntersectionObserver / idle / media / load), lazy-imports the module on trigger, and mounts it; a live re-render re-pushes changed props. Phase 1 is vanilla.ts/.jsonly (a vanilla module exportsmountitself); Vue/React/ Svelte adapters, thelive()prop bridge, and the opt-in SSR sidecar are later phases. Design: docs/design/islands.md.
v0.25.0 — 2026-10-13
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.28.0.
- Inferred type arguments for generic stateful components. The type-argument inference that v0.24.0 brought to function components now covers stateful components — struct-type tags whose pointer implements the target's
Stateful.<Box Value={7} />fortype Box[T any] struct{ ui.Live; Value T }infersT = intfrom the attribute, where before it required<Box[int] Value={7} />. Each attribute binds to its exported field, and the field's declared type (Value T,Items []T,At *T,Cols []Column[T], …) is unified structurally with the value's concrete type to pin the parameters, reusing the same unifier as the function-component path. Because Go can't infer a composite literal's type, the inferred arguments are written onto the generated literal (&Box[int]{Value: 7}). Explicit type arguments on the tag still work and take precedence; an under-constrained or conflicting tag still asks for them — now naming the conflicting parameter. Pure compile-time resolution; no runtime or JSX-contract change.
v0.24.0 — 2026-10-13
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.27.0.
- Inferred type arguments for generic JSX components. A component whose single parameter is a generic props struct —
func Table[T any](p TableProps[T]) Node— can now be used as a tag without writing its type arguments:<Table Rows={rows} Cell={fn} />infersTfrom the attribute values, where before it required<Table[User] …/>. Each attribute binds to its field, and the field's declared type (Rows []T,Cell func(T) string,Cols []Column[T],Rows []*T, …) is unified structurally with the attribute value's concrete type to pin the parameters; multi-parameter components (Pair[K, V]) are inferred from several attributes. Explicit type arguments on the tag still work and take precedence. When no attribute constrains a parameter, or two attributes imply conflicting types, the tag still asks for explicit type arguments — now naming the conflict. Pure compile-time resolution; no runtime or JSX-contract change.
v0.23.0 — 2026-10-13
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.26.0.
- Self-target JSX. A package that itself declares
const VukaJSX = 1— a JSX runtime such as a component kit — can now author JSX in its own.vukafiles. Its JSX lowers to unqualifiedEl/F/Child/… and same-package component tags (<Badge/>) resolve in-package, instead of requiring an imported target. A file that imports an external JSX target still uses it (external wins); nothing changes for apps that import a kit. No runtime or JSX-contract change.
v0.22.0 — 2026-10-12
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.25.0.
- Faster pages. JSX lowers to a lazy frame (
ui.FT) when the target declares it (ui v0.13.0 and up): the element tree moves into a build closure with the dynamics passed as arguments, so a server-rendered page writes its static HTML straight through and renders only the parts that change. A 50-row table page is about 2× faster with ~35% fewer allocations, and the HTML and the live render tree are byte-for-byte what the old lowering produced. Generated code built against an older ui still lowers the old way; nothing else changes.
v0.21.0 — 2026-10-12
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.24.0.
- Enums.
enum Status { Draft, Sent, Paid }andenum Role string { Admin = "admin", … }declare value enums withStatus.Values(),Status.Parse,String,Valid, JSON (MarshalText/UnmarshalText) anddatabase/sql(Scan/Value) methods, so an enum field works in JSON and the ORM as it is.enum Shape { Circle{Radius float64}; Empty }declares variants that carry data. Variants are reached asStatus.DraftandShape.Circle{Radius: 2}, and plain Go usesStatusDraft,ParseStatusandShapeCircle. matchtakes variants as patterns,case Shape.Circle{Radius: r}:, and a match over an enum that misses a variant is an error naming the missing ones. Patterns separated by commas may now be type tests:case Shape.Circle{}, Shape.Rect{}:.- The editor completes an enum's variants,
ValuesandParseafterStatus., with their doc comments on hover;vuka fmtlays enums out; the VS Code grammar highlights them. - Model packages link themselves. A package whose struct types embed a type with a
vukaDeclares()marker method is auto-linked like a declarer package; with orm v0.5.1, whoseBaseandModelhave it, a model package nothing imports is still registered and migrated, with no blank import. - Fixed:
SomeandNone(and statics) in a field attribute's value are qualified and inferred like any other code:@orm.Int{Min: Some(0)}. - Fixed: an attribute type's
vukaTargetsresult may be an alias or a named type of the targets array, and its targets are checked.
Libraries — 2026-10-12
- ui v0.12.0 and web v0.19.0: server-rendered HTML pages are about 40% faster, with half the allocations, and the output byte-for-byte the same. An element or frame is built in one allocation, text and attribute values are escaped only when they hold
& ' < > ", and a page with nothing live renders straight into a pooled buffer instead of through a live session. New APIui.RenderPage. - orm v0.5.1:
orm.Basemarks the types embedding it as declaring a model, so Vuka links a model's package into the program and the ORM sees models no code imports (with the next vuka release, which recognises the marker).
cmd/vuka v0.23.2 — 2026-10-12
Runtime: unchanged, v0.16.0.
- Editor: after a struct field,
@pkg.completes that package's field attributes — the types and the functions returning one, with their docs — and a half-typed field attribute no longer breaks the file's other diagnostics and hover. - New apps use web v0.18.0, whose
auth.Config.UserCachekeeps a loaded user for a while, so a signed-in request reads only its session or token;auth.Refresh(ctx, uid)drops one after a change.
v0.20.1 — 2026-10-12
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.23.1.
- Fixed: auto-linking no longer links a package under an
internaldirectory into a program outside that directory's tree (Go refuses such an import, so a module with examples failed to build). - With web v0.17.0, a live page checks the sign-in when it mounts (join, navigate) and its events read no session; sign-outs through auth close the page at once, and a periodic check (
LiveCheckEvery, 30s) catches revocations made outside auth.
v0.20.0 — 2026-10-12
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.23.0.
- Page and route packages link themselves. Every package of the module that declares something —
@web.Live,@web.Get,@web.Cron, or a composed decorator holding one — is linked into the program byvuka run,build,testandvet: no blank import to remember, and an error in such a package always fails the build. The command says what it linked (● linking 3 declarer packages (…));vuka gen -inplacewrites the same file (vuka_link_gen.go) for a plaingo build.//vuka:nolinkabove a package clause opts that package out, or, on a main package, turns linking off for that program.
v0.19.1 — 2026-10-12
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.22.2.
vuka explainshows what the build compiles. It now takes the file's generated Go from the same full transpile the build runs, so it no longer reports errors the build doesn't (a static reached through an embedded type from another package said "has no field"). A file that truly fails prints the error and exits non-zero.
cmd/vuka v0.22.1 — 2026-10-12
The vuka command only. Completion after entities.Letter. now works in a file that hasn't imported the type's package yet — picking a member also inserts the import. Restart the language server after installing.
cmd/vuka v0.22.0 — 2026-10-11
The vuka command only (vuka v0.19.0, runtime v0.16.0 unchanged). New apps use ui v0.11.0 and web v0.16.0.
- Completion knows statics.
entities.Letter.offersObjects, the fields and every static reached through embedding, with docs; hover on a static shows its declaration; the file keeps compiling while the member is half-typed. - Fixed: picking a decorator from another package in a file with no import block inserted the import before the
packageline.
Restart the language server in your editor after installing.
v0.19.0 — 2026-10-11
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.22.0. With github.com/vuka-lang/ui v0.11.0 and web v0.16.0.
- The editor completes statics. Typing
entities.Letter.offersObjects, the model's fields and every static the type reaches through embedding, with their docs; hover on a static shows its declaration. A file keeps compiling while the member is still being typed. - web v0.16.0:
Mountruns once per page view. The socket join adopts the page the HTTP render mounted when it arrives in time (web.LiveAdopt, 10s) and as the same signed-in user — so aMount's queries no longer run twice. Anything uncertain mounts fresh, exactly as before.
v0.18.0 — 2026-10-11
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.21.0.
- A faster editor.
vuka lspshows Vuka syntax errors as you type (about 1 ms, from the file being edited alone), type errors about 100 ms after you pause, and answers hover and completion without waiting for the whole module to rebuild: it keeps the transpile cachevuka run -watchuses and rebuilds the packages you edited first. Restart the language server in your editor after upgrading.
cmd/vuka v0.20.0 — 2026-10-11 — security release
The vuka command only; the language and runtime are unchanged (v0.17.0, runtime v0.16.0). New apps use github.com/vuka-lang/ui v0.10.0, web v0.15.0 and orm v0.4.0, which fix the issues a security review found. Upgrade apps with go get of those versions, and build them with Go 1.27.2 or newer.
What apps may notice:
- Live pages. A navigation keeps a page mounted only when it declares an
Updatetakingweb.URLParams— and thatUpdatemust repeat the checksMountmakes; any other page mounts again. Errors that aren't*web.Errorread "Internal Server Error" outside development (logged in full). Live connections have limits: join within 10s, idle 30m, 10,000 in all, 100 per client address, 4 per page; checks run every 30s and before broadcasts. - JS commands.
SetAttr,RemoveAttrandToggleAttrrefuse event handler attributes andsrcdoc; URL values andNavigate/Patchtake only paths and http(s) URLs. - Auth. Gated calls are strict by default (
auth.System(ctx)for jobs andmain; crons get it automatically;LaxGatesopts out). Failed logins take at least 300ms. Throttling counts per account and folds spellings. Policies matchTand*T. Live pages reload when a user's permissions change. - Requests. Security headers by default; request bodies capped at 32 MiB; forwarded headers trusted only from
web.TrustedProxies; static files never list directories or serve dotfiles;.envfiles can't setVUKA_*. - ORM. A
ReadOnlydatabase is read-only on the server; pools are capped by default (20 open);/healthzshows states only outside development;orm migrateasks before unapplying.
v0.17.0 — 2026-10-11
Runtime: unchanged, v0.16.0. The vuka command is cmd/vuka/v0.19.0. With github.com/vuka-lang/ui v0.9.0 and web v0.14.0.
- JS commands reach more elements, more safely.
ui.Refandui.Seltake several names;ui.GetAttr(name, values…)picks elements by attribute, and a literal value nothing in the component has is a compile error with a did-you-mean. Conditions combine withAnd,Or,Not,ui.All,ui.Anyand.Some();ui.JS.When(cond, chain).Else(chain)needs noEnd;ui.JS.Busy()marks a form or button busy and undoes it on a reply, a timeout or the back button. See JS commands. - Fixed: a decorated method with an unnamed receiver no longer fails to compile when a parameter is called
r. - web v0.14.0 also brings trailing-slash redirects, failed form posts that re-render the whole page, and
auth.Config.Hashersfor passwords from another system.
cmd/vuka v0.18.1 — 2026-10-11
The vuka command only. The editor no longer reports expected declaration on a method chain that goes on to the next line (ui.JS. then If(…) below it); vuka build always accepted it.
v0.16.0 — 2026-10-11
Runtime: v0.16.0 — generated code registers attributes with it; run vuka fix runtime in your apps after upgrading the vuka command. The vuka command is cmd/vuka/v0.18.0. With github.com/vuka-lang/ui v0.8.0 and web v0.13.0.
- Attributes readable from a value.
vuka.FuncOf(fn)(a method value, method expression or function),vuka.MethodAttrs(t, name)andvuka.TypeAttrs(t)return the attributes written on a declaration, so a library can read@auth.Requires(…)where it dispatches. See Reading attributes from a value. - web's auth gates checked before a live handler runs and at each gated call, with the identity carried by
ctx;auth.Config.StrictGatesrefuses a gated call that has none. See Authentication. web.IsLiveJoin(ctx)tells a live page's route it is running again for the socket's join, so side effects such as mail happen once. See Live components.
cmd/vuka v0.17.0 — 2026-10-11
The vuka command only; the language and runtime are unchanged (v0.15.0, runtime v0.10.0). New apps use web v0.12.0 and orm v0.3.0.
vuka newbuilds a working app. It asks for the UI (live pages with Tailwind, templ views, or an API), the database (SQLite by default, Postgres, MySQL, none), mail, sign-in and an optional React, Vue or Svelte frontend — or takes flags and--yes. The default app has a login page already connected to a users table and sessions in the database, an admin created from.envwith a generated password, migrations run at start, a signed-in layout with the Vuka logo, shared components, and tests that pass. See Getting started.vuka add module <name>adds a module — model, service, page, migration and test — to an app made byvuka new.
cmd/vuka v0.16.0 — 2026-10-11
The vuka command only; the language and runtime are unchanged (v0.15.0, runtime v0.10.0). With web v0.11.0: authentication, mail, crons and embedded frontends.
- Frontend apps in
vuka runandvuka build. Afrontend/package.jsonstarts the project's own Vite beside the app (dependencies installed on first run), kept running through-watchrebuilds; you open the app's address and get hot module reloading.vuka buildrunsvite buildbefore embedding. A prebuiltdistwith nopackage.jsonis served as is.
v0.15.0 — 2026-10-11
Runtime: unchanged, v0.10.0. The vuka command is cmd/vuka/v0.15.0. With github.com/vuka-lang/ui v0.7.0 and web v0.10.0.
- Styles and scripts per page.
web.Style(...)andweb.Script(...)on@web.Live,web.Layoutandweb.New(several files, globs,web.CSSandweb.JSinline,web.Globalunscoped). CSS is scoped to the component — a marker the compiler adds to its own markup, so it never travels in live diffs — with:global,:deep,:scope, scoped@keyframes, Tailwind's@applyinside, and a warning for a selector that matches nothing. Scripts are TypeScript or JavaScript, compiled by the vuka command with no Node:mounted/updated/destroyedper instance,ctx.push("Method"),ctx.on,ctx.ref, andui.JS.Callreaching them. Only methods a component's scripts name withctx.push("…")can be called by name; the compiler checks each name. See Styles and scripts. - Faster
vuka run -watch. A save answers in about 0.8–1s on a small app, down from 1.6–1.8s: file events from the operating system instead of polling, transpiling only what changed (checked against a full transpile in the tests), no debug info in watch builds (-debugkeeps it), and a save during a build cancels the stale build.
v0.14.0 — 2026-10-11
Runtime: unchanged, v0.10.0 (vuka.ObserveCalls is new in the package; generated code doesn't need it). The vuka command is cmd/vuka/v0.14.0. With web v0.9.0's development toolbar.
vuka.ObserveCallslets a tool see each step of every decorated call — each decorator, then the function — on the call's goroutine. The toolbar's Timeline uses it to show@timedand@loggedinside a request. With no observer it costs one atomic load per step.vuka runnames a session directory (VUKA_DEV_DIR). Under-watchit holds the next build's state — building, failed with the compiler's output, or ok — so the toolbar showsbuilding… 1.2sorbuild failedon the page while the last good build keeps serving.
v0.13.0 — 2026-10-11
Runtime: unchanged, v0.10.0. The vuka command is cmd/vuka/v0.13.0. With github.com/vuka-lang/ui v0.5.0 and web v0.8.0.
- Templ components diff on live pages. In a module on ui v0.5.0 or later, the vuka command compiles
.templfiles so a live render records their fixed markup apart from the values that change, as it does for JSX. An event inside a templ layout sends only what changed, and moving between pages that share a templ layout sends what differs inside it, not the whole document. Plain HTTP renders write exactly the same HTML as before; templ code compiled elsewhere still renders as one block. See templ. vuka run -watchrebuilds the app when a.vuka,.templor.gofile,go.modor an embedded file changes, and swaps it in once the build succeeds. The running app keeps serving while the next one compiles; a failed build prints its errors at the.vukaline and keeps the last good build running; a change that leaves the binary the same (a comment) restarts nothing. Tailwind keeps running through the restarts, and with web v0.8.0 live pages rejoin the new build instead of reloading. See vuka run.
v0.12.0 — 2026-10-10
Runtime: unchanged, v0.10.0. The vuka command is cmd/vuka/v0.12.0. With github.com/vuka-lang/ui v0.3.0's optimistic updates and Call and web v0.6.0, which runs them in the browser and styles pages with Tailwind.
- Tailwind for web apps, with no setup. In a module that uses web,
vuka runkeepstailwindcss --watchrunning and pages pick up each new stylesheet without reloading;vuka buildandvuka installbuild it minified into the binary;vuka genwrites the file that registers it, so a plaingo buildworks too. Classes are found in your.vuka,.templ,.htmland.gofiles and in the component packages you link. Your ownapp.css,styles/app.cssorweb.Tailwind(path)replaces the built-in stylesheet;web.NoTailwind()orVUKA_TAILWIND=offturns it off. See Styling.
v0.11.0 — 2026-10-10
Runtime: unchanged, v0.10.0. The vuka command is cmd/vuka/v0.11.0. With github.com/vuka-lang/ui v0.2.0's JS commands and web v0.5.0's browser engine for them.
- Refs. A JSX target declaring
Refgets refs:ref="menu"on an element names it for the function's code, and eachui.Ref("menu")with a literal name in a function with JSX must name one of its elements —no ref="mnu" in Menu's render; did you mean "menu"?. - The editor no longer offers gopls' deep completions (
x.Y().Z) as a props struct's attributes.
v0.10.1 — 2026-10-10
Runtime: unchanged, v0.10.0. The vuka command is cmd/vuka/v0.10.1.
- A dependency that doesn't compile is reported as such, once, at the import that needs it, with its own error and file — not as "no export data" on every package above it. A dependency built for an older Vuka gets a hint (
web v0.3.0 was built for an older Vuka; upgrade it (go get …@latest)); code of your own written for one,run vuka fix ui. Healthy packages are no longer blamed, and errors that only follow from a failed import ("its type is unknown") are left out. The editor shows the same.
v0.10.0 — 2026-10-10
Runtime: github.com/vuka-lang/vuka v0.10.0 — the UI layer is gone from it. New library: github.com/vuka-lang/ui v0.1.0. Run vuka fix ui.
- JSX targets. JSX is syntax; what it renders with is a library the file imports, its JSX target: a package declaring
const VukaJSX = 1andNode,El,Text,Child,Fragment,Nodes,Try(optionallyOn,Stateful+Component,WithChildren,F). A file with JSX imports one target; without one it is a compile error saying so. Component resolution, attribute binding, generic and overloaded components are checked against the target's declarations; event payload rules,Mount's shape and*Liveembedding are the target's runtime checks now. github.com/vuka-lang/ui: everything that wasvuka.Node,vuka.Live,vuka.Event,vuka.Assign,vuka.Tree,vuka.String, … and thelive,live/livetest,termandtemplxpackages, unchanged but for the package name.vuka.TemplComponent,RegisterTemplandTemplComponentsaretemplx.Component,RegisterandComponents.vuka fix uirewrites a module: names, imports, the ui import in every.vukafile with JSX,go get github.com/vuka-lang/ui.- The runtime requires nothing (no templ) and needs Go 1.23.
- The vuka command is its own module,
github.com/vuka-lang/vuka/cmd/vuka(go install github.com/vuka-lang/vuka/cmd/vuka@latestas before). It compiles.templfiles with templ's parser and generator — a plugin of the command, on for modules that require templ. - Decorators: optional arguments, parameter attributes, composition, type-level advice and attribute targets.
- A decorator whose parameters are all optional can be written bare:
@transactioncallstransaction(), and@transaction(On("db"))is the same decorator with settings. - Parameter attributes:
func Show(@Path("id") id int, @Body in NewPet), read by declarers (vuka.Param.Attrs) and call decorators (c.ParamAttr(i, &x)). - Composed decorators:
decorator ApiRoute(path string) = @web.Get(path) @web.Use(auth) @timed, exported and used like any decorator. - Type-level advice: a call decorator on a type wraps every method of it declared in
.vukafiles;@vuka.NoAdviceopts a method out. - Attribute targets:
@vuka.Targets(vuka.OnField)on an attribute type makes using it elsewhere a compile error. Decorators, Attributes.
- A decorator whose parameters are all optional can be written bare:
- VS Code extension 0.4.2: highlighting for parameter attributes and composed decorators.
- Docs: UI is its own section; the language's JSX page is library-neutral; Live protocol is the reference for transport authors.
v0.9.0 — 2026-10-10
Runtime: github.com/vuka-lang/vuka v0.9.0 (vuka fix runtime upgrades). New vuka.Frame/vuka.F (JSX's compile-time shape), vuka.Tree, vuka.TreeList, vuka.TreeRef, vuka.BuildTree, vuka.Assign, vuka.RootAttrs; live.Session.RenderTrees, HTML, live.TreeUpdate, live.Verify, live.Marshal, package live/livetest. Generated code needs it: JSX now lowers through vuka.F.
- Live render trees (protocol v2). A client joining with
{"type":"join","v":2}gets each instance's render tree — statics sent once per connection, dynamics, block items, instance references — and after an event only the changed dynamics: list steps with keyed moves, branch switches, long markup by reference or token patch. v1 clients are unchanged. A one-cell change in a 1000-row table is 89 bytes instead of 122 KB. See Protocol v2. vuka.Assign[T]: a component whose state is all Assigns is rendered again only when one is set or its props change; tests verify skipped components against a full render (VUKA_LIVE_VERIFY).live/livetest, a reference client of both protocol versions in Go.- Fixed: a stateful component tag with an expression key (
<Row key={i} />) crashed the compiler. - Server messages are written without HTML escaping (
<rather than\u003c); the JSON is the same once parsed. vuka gen -inplacewrites line directives relative to the generated file, so committed generated code no longer carries the checkout's path.- vuka-lang/web v0.3.0 speaks protocol v2 in the browser.
v0.8.0 — 2026-10-10
Runtime: unchanged, v0.7.0.
- Seamless JSX editing. Completion for every HTML element (and SVG basics) with descriptions, each element's own attributes before global ones, event handlers,
aria-*/data-*, enumerated attribute values, closing tags, and{for}/{if}/{match}blocks with placeholders; hover on elements and attributes with MDN links; linked editing renames a tag's closing tag as you type; JSX elements and blocks fold; at most one diagnostic while a tag is half-typed. - Statics: a generic type's static takes any initializer —
&Store[Self]{},NewStore[Self](),new(Store[Self]), literals — with its type inferred,Selfper instantiation. - VS Code extension 0.4.1: closing tags after other tags on a line and inside attribute braces,
{pairs inside elements, Enter indents between tags,editor.linkedEditingon for.vukafiles. - Docs: the language pages are library-free; the web framework and the ORM have their own sections.
v0.7.0 — 2026-10-10
Runtime: github.com/vuka-lang/vuka v0.7.0 (new: vuka.Live, vuka.Component, vuka.On, vuka.Event, the live package; field references vuka.Ref with OrderedRef, StringRef, CompareRef, NullableRef, vuka.Pred, vuka.Order, vuka.FieldPath, vuka.Related, vuka.FieldAttrs, vuka.FieldsOf; vuka.Field has Attrs).
- Stateful components. A struct embedding
vuka.Live, withMount,Renderand event handlers:<Counter Start={5}/>keeps its state on the server,onClick={c.Inc}(methods or closures, values, form structs) runs there, and only the components that changed are sent back. Components nest,keykeeps list items attached,Update(msg)overloads receive broadcasts. Rendered without a session they are plain HTML. Thelivepackage is the transport-independent session; vuka-lang/web serves it over WebSocket. Stateful components. - Field attributes. Typed attributes after a struct field, after its tag:
Title string `json:"title"` @Char{Max: 200}, recorded at init. Field attributes. - Field references.
Post.Titleis a typed reference to the field;Post.Author.Namefollows struct, pointer andvuka.Relatedfields. They build typed predicates (Post.Views.Gt(100)) and orderings, the foundation of vuka-lang/orm's queries. Field references. - JSX: brace-less
if/for/matchinside block bodies; JSX in package-level variables; props from embedded struct fields; a block header may hold composite literals. - Statics may use other statics, field references and
Selfin their initializers; initialization cycles are reported with their chain. - match: exhaustiveness checks nested patterns (
Ok(Some(p)),Ok(None),Err(e)), and amatchon a value fromx := f()?sees its unwrapped type. - Errors quote field references and statics as the source spells them.
- Editor:
vuka.Filepaths are links (click to open, hover lists a.templfile's components); positions stay right while a file with several edits doesn't compile; completion offers stateful components, their props and event handlers. - VS Code extension 0.4.0: highlighting for field attributes, match patterns, JSX blocks, events and component tags; 16 snippets (components, routes, live pages, ORM models, transactions); auto-closing tags; the vuka version in the status bar.
v0.6.0 — 2026-10-10
Runtime: github.com/vuka-lang/vuka v0.6.0 (new: vuka.Decl, vuka.File, vuka.TemplComponent).
- Declaration decorators. A decorator of type
func(*vuka.Decl)— or a call returning one, such as@web.Get("/pets/{id}")— runs once at init with the function's name, attributes, parameter names and types, and the function itself: the way to register routes, commands or jobs without wrapping calls. Decorators. vuka.File. A string literal where a decorator or attribute takes avuka.Fileis checked when the program compiles (it must exist, in the package's directory or below) and embedded in the binary. For a.templfilevuka.TemplComponents(f)gives its components with their parameter names; a.templfile may sit in a subdirectory that is its own package (views/pets.templ,package views), which Vuka compiles and imports. Files.- The export-data cache no longer keeps modules replaced by a directory (
replace … => ../vuka), which could serve a stale runtime. - vuka-lang/web, a web framework built on declarers: routes from
@web.Get, handler parameters bound from the path, query and body, dependencies injected, results rendered as JSON or through@web.Templateviews (.html,.templor JSX).
v0.5.0 — 2026-10-10
- Components and JSX. Markup is an expression in
.vukafiles; components are functions, with attributes bound to parameters by name or to a props struct,{for},{if}and{match}blocks, and errors at the tag. Components and JSX. - Rendered by templ.
vuka.Nodeistempl.Component: Vuka components and templ components call each other, and.templfiles compile with the rest of the package (notempl generate), with editor support mapped into them. - Components can be generic (type arguments inferred, or
<List[User]>) or overloaded;?andmatchwork inside{…}; a Vuka component that would drop its children is an error. vuka.Handler,vuka.Write,vuka.String; a walkable node tree (vuka.Walk,vuka.Renderer) and a terminal renderer,vuka/term, which lays out templ components' HTML too.vuka fmt: Go as gofmt prints it, JSX Prettier-style, never changing what a page renders. Format on save in the editor.- Editor: completion after
<, in a tag's attributes and after</; hover, go to definition and rename on tags, closing tags and attributes; a tag being typed no longer breaks the rest of the file. - templ's language server can use vuka as its gopls, so
.templfiles see code from.vukafiles. - VS Code extension 0.3.0: JSX highlighting, templ's icon for
.templfiles, format on save, and an offer to serve.templfiles through Vuka.
Breaking: the decorator helper vuka.Attr[T](c) is now vuka.AttrOf[T](c) (vuka.Attr is JSX's attribute). vuka fix attr-of rewrites it. Go 1.25 or newer is required (templ needs it).
Runtime: v0.5.0.
v0.4.1 — 2026-10-10
vuka mod:go modthat sees the imports of.vukafiles.vuka mod tidykeeps requirements plaingo mod tidywould drop.- Editor: a hover or go-to-definition gopls can't answer (a broken import, code mid-edit) is now no answer instead of an error, and VS Code no longer opens the output panel on errors.
- An import nothing provides that names a folder of your module gets a hint: it's in this module: import "hello/data".
Runtime: v0.3.0.
v0.4.0 — 2026-10-10
- One gopls. Run as
gopls, vuka is a drop-in gopls, so.gofiles in a package with.vukafiles see their code; every editor session shares one gopls daemon. vuka explainshows each line beside the Go it becomes.vuka fix:runtime,static-names,orphans.- Faster builds: one
go listper build, export data cached across builds. - Workspaces reached through symlinks.
- This documentation site.
Runtime: v0.3.0.
v0.3.1 — 2026-10-09
- Typing
@lists the project's decorators, narrowing as you type.
v0.3.0 — 2026-10-09
- Dependency injection: a type decorator on a struct gets
t.New, a constructor taking its dependency fields (inject:"-"opts out). - Picking a decorator after
@inserts its name; a factory gets a call.
Runtime: v0.3.0.
v0.2.1 — 2026-10-09
- Completion keeps working while an
@line is being typed; code actions over attributes no longer fail; a clear message when the runtime is too old.
v0.2.0 — 2026-10-09
- Python-style decorators:
decorator name(c) { … },c.Next,c.Return,c.Err,c.Context,c.Attr; type decorators. - Statics and static methods, statics of generic types and through embedding; Self inference;
selfmethods.
Runtime: v0.2.0.
v0.1.1 — 2026-10-09
- The language server works beside VS Code's Go extension.
v0.1.0 — 2026-10-09
- Result and Option,
?,match, overloading, attributes,@export. vuka build,run,test,gen,new; thebuild/module.vuka lspand the VS Code extension.