Skip to content
liustackPublic

About

Go + QuickJS React SSR framework

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

tifa

The full-stack framework for Gophers.

简体中文 · Writing an app · Build and run · Dev server · Example app

Follow @liustack on X Go reference Go version CGO off License Not backed by Y Combinator Users unknown

Write the backend in Go and the pages in React. tifa compiles the whole site into one executable that you copy to a small VPS and run. No Node in production, no process manager, no reverse proxy, no Redis.

It is for Go developers whose business logic and data already live in Go, who want to write pages with the React ecosystem, and who do not want to keep a Node service running in production just for server-side rendering.

tifa is very early. APIs will change, and many compiler optimizations are not done yet.

Why it exists

I wanted to ship a small product on TanStack Start. My other VPSes were full, Black Friday was still weeks away and I did not feel like buying another one, so I dug out an old box with 1 CPU and 1 GB of RAM. I had Codex set up the usual stack in one go: nginx, Node.js, PM2, TanStack Start, Redis, BullMQ, cron and SQLite.

It did not really run. It crawled.

So I started hacking on tifa. Once it is done, deploying should mean copying one Go binary to the VPS, and that is it.

On a 1 CPU / 1 GB VPS The usual stack With tifa
Reverse proxy nginx The Go HTTP server in the binary
Runtime and process manager Node.js + PM2 One Go executable
React SSR TanStack Start TanStack Router, rendered by a pure Go QuickJS inside the Go process
Cache Redis An in-process HTML cache, plus whatever you keep in Go memory
Queues and scheduled jobs BullMQ + cron Goroutines you start in OnStart
Database SQLite SQLite, with a pure Go driver so CGO stays off

I still do not know what to call it. A React SSR framework with no Node runtime? A React SSR framework with a Go backend? Both sound a little unhinged. Under the hood it is Go, a pure Go build of QuickJS, and TanStack Router.

What it looks like

One folder per page. Go loads the data, React shows it:

// app/projects/project+/orders/order+/route.go  →  /projects/{project}/orders/{order}
func Load(c *tifa.Ctx) (orders.Order, error) {
	return orders.GetOrder(c.Param("project"), c.Param("order"))
}
// app/projects/project+/orders/order+/route.tsx
import { route, type Data } from './+route'

export default function OrderPage() {
  const order = route.useLoaderData() // typed from the Go return value
  return <h2>{order.id}</h2>
}

// title and meta tags are written into the HTML on the server
export const head = ({ loaderData }: { loaderData?: Data }) => ({
  meta: [{ title: `Order ${loaderData?.id}` }],
})
go get -tool github.com/liustack/tifa/cmd/tifa
go tool tifa dev     # hot-reloads components, restarts on Go changes
go tool tifa build   # bin/<app>, with the frontend embedded

Highlights

  • One file to deploy. Pure Go, CGO_ENABLED=0, cross-compiles like any Go program. The browser bundle, styles and server renderer are embedded in the executable.
  • Real HTML on the first request. Go runs the page's Load and every Layout function first, then renders React to complete HTML inside the process with a pure Go QuickJS. Search engines and link previews see the content, title and meta tags. Each page renders whole in one pass: there is no streaming and there are no React Server Components.
  • Your frontend tools keep working. Vite, Tailwind and shadcn work as usual on your machine. The server runs one Go file and never installs Node.
  • Types from Go to React. The TypeScript type of each page's data is generated from what its Go Load returns.
  • Mistakes caught at build time. Duplicate paths, a Layout reading a parameter it does not own, a Load result that cannot become TypeScript: the build stops and names the file and line.
  • Fast after the first page. TanStack Router takes over in the browser. Each navigation is one request for data, and Layouts that are already loaded are not fetched again.

Start an app

You need Go 1.27, Node 20.19 or 22.12 and later (what Vite 8 asks for) and pnpm (npm works too). Node only builds the front end: the program you deploy never needs it. tifa dev does not run on Windows yet, use WSL.

go run github.com/liustack/tifa/cmd/tifa@latest new myapp
cd myapp
go mod tidy
pnpm install
go tool tifa dev     # http://127.0.0.1:9527

The first tifa dev compiles QuickJS and SQLite once, which can take a minute or two. Later builds use Go's build cache.

tifa new writes a home page with a Go Load, a POST the page calls from the browser, and a test of both. The module path is the folder name unless you pass --module example.com/myapp.

Try the example

examples/shop is a small order workbench: two shops, an order list, order details, a shipping form, sales stats with charts, and three kinds of 404. You need Go 1.27, Node 20.19 or 22.12 and later, and pnpm:

cd examples/shop
pnpm install --frozen-lockfile
go tool tifa build
./bin/shop           # http://127.0.0.1:9527

Documentation

Doc Read it when
Philosophy You want to know why a tifa app is organized the way it is
Structuring an app Deciding where domain code, storage and shared resources go, and which way packages may import each other
Writing an app Laying out folders, routes, Layouts, hooks, 404 pages, head tags and caching
Build and run You want to know what tifa build generates and how the program answers requests
Dev server Running tifa dev locally, or a change did not reload
Configuration Deploying: the port, body limit, VMs, render timeout and page cache
Testing Contributing to tifa itself

Talk to us

Issues are welcome any time: open one. Tell us what you built, where it hurt, and what should come next. Come find me on X: @liustack.

Contributing

tifa does not accept pull requests. A framework like this touches the compiler, the bundler, server rendering and developer experience at once, and a change in one pulls on the others. Getting that right takes a lot of context, so every line is written and reviewed by one author. Two ways to help:

  • Open an issue. Bugs, ideas, confusing errors, unclear docs. A clear issue with steps to reproduce helps more than a patch, and issues shape what gets built next.
  • Fork it. Under MIT your copy is yours to change and publish.

Star History

Star History Chart

License

MIT. A program built with tifa embeds Unicode CLDR locale data, whose notices go with the program when you distribute it, see docs/build.md.

About

Go + QuickJS React SSR framework

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages