zeekay dd46954b01 A record's history, written in the record's own transaction
A base collection that turns History on gets a _history row for every
create, update and delete: the collection and record ids, the action, the
writer (an actor field stamped from the save's context) and each changed
field's from and to. The row and the record commit or roll back together.
id, autodate, actor and hidden fields are left out, a value over 4 KiB is
recorded only as changed, and one writer's updates to one record within ten
minutes fold into one entry.

GET /v1/collections/{collection}/records/{id}/history reads it, newest
first, for whoever the record's view rule admits.
2026-10-18 21:25:32 -07:00
2026-05-25 15:14:54 -07:00
2026-09-11 13:58:52 -07:00
2025-02-10 11:58:49 -06:00
2026-09-08 23:53:19 -07:00

Base

Base

Base is a backend in one Go binary: collections of records behind a REST API at /v1, with realtime updates, files, per-collection access rules and JavaScript hooks, stored in SQLite. Identity comes from Hanzo IAM, and with IAM on, each org's data lives in a database file of its own.

Run it

You need Go 1.26.8 or newer.

git clone --depth 1 https://github.com/hanzoai/base
cd base/examples/base
CGO_ENABLED=0 go build

Describe a collection in a migration. Base applies migrations when it starts.

mkdir -p base_/migrations
cat > base_/migrations/1_notes.js <<'EOF'
migrate((app) => {
  app.save(new Collection({
    type: "base",
    name: "notes",
    listRule: "",
    viewRule: "",
    createRule: "",
    fields: [{ name: "text", type: "text", required: true }],
  }))
})
EOF
./base serve --http 127.0.0.1:8090
Server started at http://127.0.0.1:8090
├─ REST API:  http://127.0.0.1:8090/v1/
└─ Dashboard: http://127.0.0.1:8090/

From a second terminal, create a record and list the collection:

curl -s -X POST http://127.0.0.1:8090/v1/collections/notes/records \
  -H 'Content-Type: application/json' -d '{"text":"hello"}'
{"collectionId":"hbc_3395098727","collectionName":"notes","id":"kbx358lmic2a4bw","text":"hello"}

curl -s http://127.0.0.1:8090/v1/collections/notes/records
{"items":[{"collectionId":"hbc_3395098727","collectionName":"notes","id":"kbx358lmic2a4bw","text":"hello"}],"page":1,"perPage":30,"totalItems":1,"totalPages":1}

The empty rules let anyone read and write notes; docs/rules.md shows how to close them. The data is in base_/data.

The startup output has two stale lines. The Dashboard address answers only when BASE_ENABLE_ADMIN_UI=1 is set, and the hint to run superuser upsert names a command that was removed. Superusers come from IAM.

Use it as a Go library

In an empty directory, save this as main.go:

package main

import (
	"log"

	"github.com/hanzoai/base"
	"github.com/hanzoai/base/core"
)

func main() {
	app := base.New()

	app.OnServe().BindFunc(func(se *core.ServeEvent) error {
		se.Router.GET("/hello", func(re *core.RequestEvent) error {
			return re.String(200, "Hello")
		})
		return se.Next()
	})

	if err := app.Start(); err != nil {
		log.Fatal(err)
	}
}
go mod init example.com/hello
go mod tidy
CGO_ENABLED=0 go build
./hello serve

GET http://127.0.0.1:8090/hello then answers Hello, next to the whole /v1 API.

Page For
docs/versions.md which tags serve what, and moving from /api and passwords to /v1 and IAM
docs/rules.md access rules, identity from IAM, orgs
docs/hooks.md JavaScript hooks and migrations
docs/config.md every command, flag and environment variable
docs/listeners.md every socket Base can open
docs/threat-model.md what Base defends, and what you configure
examples/hooks-hybrid-search full-text and vector search written as hooks

Clients

  • JavaScript and TypeScript: @hanzo/base. Give it the origin, as in new BaseClient('http://127.0.0.1:8090'); it adds /v1 itself.
  • Dart: hanzo-dart/base.

Contributing and security

CONTRIBUTING.md covers building and testing. Report vulnerabilities as SECURITY.md describes. Base is MIT licensed; see LICENSE.md.

S
Description
No description provided
Readme
132 MiB
Languages
Go 94.5%
TypeScript 3.9%
JavaScript 0.6%
CSS 0.4%
Rust 0.3%