Tern

module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 10, 2026 License: MIT

README

Tern

Svelte on the client. Go on the server.
A full-stack web framework with file-based routing, typed data loading and single-binary deploys.

CI Go Reference Docs

[!NOTE] Tern 1.0 is stable: minor releases do not break the public API. See the stability promise.


Why Tern?

SvelteKit has one of the best developer experiences on the web, but its server code runs on Node. Tern keeps the parts that make SvelteKit pleasant, such as file-based routes, load functions, form actions and layouts, and runs everything server-side in Go.

  • Real Svelte 5. Not a lookalike. Your components, the Svelte ecosystem and your editor tooling all keep working.
  • Go on the server. load functions and form actions are plain Go, built on net/http.
  • End-to-end types. The structs your Go Load returns become TypeScript types for your Svelte pages, generated automatically.
  • Server-side rendering. Pages render in Go through an embedded JavaScript engine and hydrate in the browser. No Node in production.
  • One binary. tern build embeds the client and the renderer into a single static Go executable.
  • Progressive enhancement. Forms work without JavaScript, and get better with it.

Getting started

You need Go 1.26+ and Node.js 22+.

go run github.com/Unfield/Tern/cmd/tern@latest new my-app
cd my-app
npm install
npm run dev

Open http://localhost:5173. npm run build produces build/my-app, a single binary that serves the whole app.

A taste

src/routes/
├── +layout.svelte
├── +page.svelte
└── blog/slug.param/        # → /blog/[slug]
    ├── page.server.go
    └── +page.svelte
// src/routes/blog/slug.param/page.server.go
package page

import "github.com/Unfield/Tern/kit"

type Data struct {
	Title string `json:"title"`
	Body  string `json:"body"`
}

func Load(ctx *kit.Ctx) (Data, error) {
	post, err := posts.Find(ctx.Param("slug"))
	if err != nil {
		return Data{}, kit.NotFound()
	}
	return Data{Title: post.Title, Body: post.Body}, nil
}
<!-- src/routes/blog/slug.param/+page.svelte -->
<script lang="ts">
  import type { PageProps } from './$types';
  let { data }: PageProps = $props(); // fully typed from the Go struct
</script>

<h1>{data.title}</h1>
<article>{data.body}</article>

Dynamic directories use Go-safe names, because Go import paths cannot contain brackets: slug.param for [slug], lang.optional for [[lang]], path.rest for [...path], and app.group for (app). See examples/todos for a complete app with sessions, form actions, a protected route group and an API endpoint.

Status

Milestone Scope State
v0.1 Router, loads, actions, endpoints, typegen, dev server, single-binary build Done
v0.2 Server-side rendering and hydration Done
v0.3 Prerendering, streaming, deployment guides Done
v0.4 Typed links, navigation hooks, selective reloading, CSP, a shadcn-svelte dashboard example, docs site Done
v1.0 Plugins, base paths, public environment variables, the stability promise Done
v1.1 Translations, responsive images, service workers, sessions, metrics, rate limiting and CORS plugins Done

Documentation

Contributing

Contributions are welcome. Please read CONTRIBUTING.md and our Code of Conduct first. To report a security issue, follow SECURITY.md.

License

MIT © The Tern Authors

Tern is an independent project and is not affiliated with or endorsed by the Svelte team.

Directories

Path Synopsis
cmd
tern command
Command tern is the command-line interface for the Tern framework.
Command tern is the command-line interface for the Tern framework.
internal
codegen
Package codegen generates the code that connects a Tern app's routes to the runtime: tern.gen.go for the Go server, the client route manifest for Vite, and TypeScript types for every route.
Package codegen generates the code that connects a Tern app's routes to the runtime: tern.gen.go for the Go server, the client route manifest for Vite, and TypeScript types for every route.
i18n
Package i18n formats translated messages.
Package i18n formats translated messages.
routes
Package routes discovers Tern routes on the filesystem and matches URLs against them.
Package routes discovers Tern routes on the filesystem and matches URLs against them.
ssr
Package ssr renders Svelte pages on the server by running the app's server bundle in embedded QuickJS VMs.
Package ssr renders Svelte pages on the server by running the app's server bundle in embedded QuickJS VMs.
ui
Package ui formats the Tern CLI's terminal output: colors, symbols, spinners and tables.
Package ui formats the Tern CLI's terminal output: colors, symbols, spinners and tables.
version
Package version reports the version of the Tern build.
Package version reports the version of the Tern build.
Package kit is the server runtime for Tern applications.
Package kit is the server runtime for Tern applications.
plugins
compress
Package compress gzips a Tern app's dynamic responses (pages, data, endpoint JSON) for clients that accept it:
Package compress gzips a Tern app's dynamic responses (pages, data, endpoint JSON) for clients that accept it:
cors
Package cors lets other origins call a Tern app's endpoints:
Package cors lets other origins call a Tern app's endpoints:
health
Package health adds liveness and readiness endpoints to a Tern app:
Package health adds liveness and readiness endpoints to a Tern app:
metrics
Package metrics exposes Prometheus metrics for a Tern app, with no dependencies:
Package metrics exposes Prometheus metrics for a Tern app, with no dependencies:
ratelimit
Package ratelimit limits how often each client can call a Tern app:
Package ratelimit limits how often each client can call a Tern app:
requestlog
Package requestlog logs every request a Tern app serves, with slog:
Package requestlog logs every request a Tern app serves, with slog:
secure
Package secure sets security headers on every response of a Tern app:
Package secure sets security headers on every response of a Tern app:
sessions
Package sessions stores per-user data in an encrypted cookie:
Package sessions stores per-user data in an encrypted cookie:

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL