sveltego Svelte Themes

Sveltego

SvelteKit-shape framework for Go. Native runtime, zero JS server. Codegen .svelte to Go.

sveltego

SvelteKit-shape framework for Go. Pure-Svelte templates, Go-only server, zero JS at runtime.

Write your UI in Svelte 5. Write your server in Go. Deploy a single Go binary — no Node, no Bun, no JS engine on the request path. File layout and DX mirror SvelteKit (file-based routing, server-side data loaders, layouts, hooks, form actions).

Pre-alpha. Expect rough edges. Pin the versions in the quickstart.

Quickstart

go run github.com/binsarjr/sveltego/packages/init/cmd/[email protected] ./hello
cd hello
go install github.com/binsarjr/sveltego/packages/sveltego/cmd/[email protected]
sveltego build && ./build/app                                  # listens on :3000

sveltego build chains codegen → Vite → go build in one step. No separate go build invocation needed.

Useful flags on sveltego-init:

  • --ai — emits AGENTS.md, CLAUDE.md, .cursorrules, and Copilot rules
  • --tailwind=v4|v3|none — opt into Tailwind
  • --service-worker — starter src/service-worker.ts

Full annotated walkthrough: docs/guide/quickstart.md.

From-source path (clone the repo)
git clone https://github.com/binsarjr/sveltego
cd sveltego
go install ./packages/sveltego/cmd/sveltego
go install ./packages/init/cmd/sveltego-init
sveltego-init ./hello

How it looks

Templates are 100% pure Svelte/JS/TS. No Go syntax inside .svelte files:

<script lang="ts">
  let { data } = $props();
</script>

<h1>Hello {data.user.name}</h1>
{#if data.posts.length > 0}
  <ul>
    {#each data.posts as post}
      <li>{post.title}</li>
    {/each}
  </ul>
{/if}

A sibling Go file owns the data shape:

type PageData struct {
    User  User   `json:"user"`
    Posts []Post `json:"posts"`
}

func Load(ctx kit.LoadCtx) (PageData, error) {
    return PageData{User: fetchUser(ctx), Posts: fetchPosts(ctx)}, nil
}

Codegen reads the Go AST and emits a .svelte.d.ts declaration so Svelte LSP autocompletes data.user.name end to end. JSON tags drive field names at the Go ↔ TypeScript boundary; kit.Streamed[T] maps to Promise<T[]> for native {#await} blocks.

Render modes

Pick a mode per route by setting fields on kit.PageOptions in _page.server.go. SSR is the default. Layouts cascade; page-level overrides win.

Mode When to use Recipe Runtime path
SSR (default) Dynamic, fresh data per request Default — no opt-in needed Go Render() emits HTML; client hydrates
SSG Marketing, docs, blog kit.PageOptions{Prerender: true} Build-time HTML; static handler at runtime
SPA Authenticated dashboards kit.PageOptions{SSR: false} App shell + JSON payload; client renders
Static No per-page data No _page.server.go; pure .svelte only App shell + empty payload; client renders
// SSR (default)
func Load(ctx kit.LoadCtx) (PageData, error) {
    return PageData{Posts: fetchPosts(ctx)}, nil
}
// SSG
const Prerender = true

func Load(ctx kit.LoadCtx) (PageData, error) {
    return PageData{Title: "About"}, nil
}
// SPA
const SSR = false

func Load(ctx kit.LoadCtx) (PageData, error) {
    return PageData{User: currentUser(ctx)}, nil
}

Full reference + decision tree: docs/render-modes.md.

Learn more

Community

Top categories

Loading Svelte Themes