# Zen, a self-hosted notes app that keeps your notes as Markdown in SQLite

> Zen is a self-hosted note taking application that ships as a single Go binary or a Docker Compose stack, stores notes as standard Markdown in a local SQLite database, and adds BM25 ranked full-text search, tags instead of folders, templates, pinned and archived notes, version history and internal note links with a side panel preview. It also exposes an MCP server for searching, listing and reading notes.

**sheshbabu/zen** — Selfhosted notes app. Single golang binary, notes stored as markdown within SQLite, full-text search, very low resource usage

- Repository: https://github.com/sheshbabu/zen
- Website: https://www.sheshbabu.com/zen/
- Stars: 1,190 · Forks: 64
- Language: JavaScript
- License: AGPL-3.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/sheshbabu-zen

## One binary, Markdown in SQLite

Zen is a self-hosted notes application, and the design choice that defines it is that the notes are standard Markdown files held in a local SQLite database, delivered either as a single Go binary or through Docker Compose. The feature list is built on that: low resource usage, a minimal dependency footprint, and full-text search with BM25 ranking. The consequence for the person using it is that a note is not an opaque row in someone else's database format, it is Markdown, and the application is a reader and writer for a format you can open in any other editor. The alternative worth comparing is a note application that stores rich text or a proprietary structure, where migrating away later means an export, and where the export is often lossy. Zen's answer is that there is nothing to export, because the storage format is already the interchange format. The primary language recorded for the repository is JavaScript, which refers to the front end, and the Go module and the main.go file at the root show the server side.

```shell
$ make build
```

## Tags rather than folders, and what else ships

Organisation is deliberately not folder-shaped. Notes are organised with flexible tags, not rigid folders, which is a small choice with a large effect on how a note taking application ages: a folder hierarchy has to be restructured as a collection grows, while a tag set can simply grow a dimension. The rest of the feature list covers the things a note application is judged on. Markdown features are supported, including tables, code blocks, task lists and highlights. There are templates, pinned notes, archive and soft delete, bulk archive and delete, and version history, which together mean the application keeps the note history rather than only the current state. Internal note links with a side panel preview let one note reference another and show it without leaving the page. Import and export is listed with full portability, and the automated backups are handled by a separate project, Zen Backup, with importing from other services handled by Zen Import.

```
* Organize with flexible tags, not rigid folders
* Templates
* Pinned notes
* Archive and soft delete notes
* Version history
* Internal note links with side panel preview
```

## Search with BM25, and the experimental layer on top

Search is full-text with BM25 ranking, which is the part of the feature list that has a specific algorithmic commitment: the results are ordered by term frequency and inverse document frequency rather than by recency or by a substring match. The experimental features are a separate list, and that separation matters because they are the parts most likely to change. The experimental set includes a canvas for spatial organisation of notes and images, stored in the JSON Canvas format, semantic search for notes and images and similar images, both delivered by a project called Zen Intelligence, and an MCP server for searching, listing and reading notes. The MCP server is the one with the widest reach outside the application, because it is what lets another tool, an assistant, read and query your notes programmatically rather than through a user interface.

```
* MCP for searching, listing and reading notes
```

## The Docker image, and why the FTS5 tag matters

The Dockerfile is a two-stage build that explains the deployment model and one important constraint. The builder stage is a Go 1.24 image on bookworm with the cross compilers for aarch64 installed, and it installs esbuild from source as a binary, because the front end is JavaScript that has to be bundled. The bundle step runs esbuild over index.js producing a minified ES module with a JSX loader, and then the Go build runs with CGO enabled, the cross compiler chosen per target architecture, and the build tag fts5, which is the SQLite full-text search extension. The runtime stage is a debian bookworm slim image with only the compiled binary copied in, two volumes for the data folder and the images folder, and the corresponding environment variables pointing at them. So the shipped artefact is one static binary plus a data directory, and the FTS5 tag is not optional if you want the search the feature list describes.

```dockerfile
FROM --platform=$BUILDPLATFORM golang:1.24.0-bookworm as builder

RUN go install github.com/evanw/esbuild/cmd/esbuild@latest

RUN esbuild index.js --bundle --minify --format=esm --outfile=assets/bundle.js --loader:.js=jsx --jsx-factory=h --jsx-fragment=Fragment
go build --tags "fts5" -v -o ./zen .
```

## Development, migrations and how the schema changes

The local development setup is two make targets and two installed tools. Running the application with the default configuration is make dev, and the watch mode needs air, the Go live reload tool, and esbuild, both installed with go install. The schema change process is spelled out simply: create a new migration file under the migrations directory, using the format of a version, an underscore and a title, then a .sql extension. That is a plain SQL migration setup with no ORM in the loop, which matches the rest of the project. The Go module itself is small. It requires the uuid package, go-sqlite3, the crypto package and the image package, with Go 1.24 and a toolchain line pinning 1.24.7, so the runtime dependency set for a note application with search, image handling and password hashing is four modules. The front end is built on Preact, with the standalone Preact builder, markdown-it, highlight.js, Lucide icons, a CSS reset and Konva.js credited in the acknowledgements.

```shell
$ go install github.com/air-verse/air@latest
$ go install github.com/evanw/esbuild/cmd/esbuild@latest
```

## The repository layout, and the licensing

The tree is organised by concern rather than by language. There are commons/, features/ and docs/ directories, a migrations/ directory, a Dockerfile, a makefile, main.go, index.js, the go.mod and go.sum, and both license.md and a license file in the top level. The features/ directory is the interesting one for a reader, because it suggests the application is assembled from feature modules rather than one large main package. The index.js at the root is the front end entry point that esbuild bundles, which is why the Dockerfile installs esbuild rather than shipping node_modules. The licence is AGPL-3.0, which for a self-hosted network application is a meaningful constraint: if you modify it and offer it over a network, the source of your modified version has to be available. That is the reason to read the licence file rather than assume it behaves like the MIT licence of a typical utility.

```
commons/
features/
docs/
migrations/
main.go
index.js
go.mod
```

## A personal project, and what that means in practice

The contributions section is one paragraph and it sets expectations. This is a personal project built for the author's own use, the codebase is available for forking and modifications, and the author notes that they may not actively review pull requests or respond to issues due to time constraints. That is a fair and clearly stated position, and it is worth taking at face value when you evaluate the project, because it changes what the project is and is not. It is not a product with a support commitment, and the absence of GitHub releases means there is no versioned artefact to pin. What it is, on the other hand, is a complete, well-shaped application: one binary, four Go dependencies, a bundled front end, SQL migrations, a documented search implementation, an experimental MCP surface and a companion set of projects for backup, import and intelligence. The last push was on 2026-10-15 and the repository is not archived, so the work continues even where the review bandwidth does not.

```
This is a personal project built for my own use. The codebase is
available for forking and modifications.
```

## Conclusion

Adopt Zen if you want a notes application you host yourself, where the notes stay as readable Markdown in a local database and you can add machine access to them through an MCP server, and skip it if you need collaborative editing or a mature mobile client, because the project describes itself as a personal project built for the author's own use. Verify three things before you rely on it: that the AGPL-3.0 licence fits your situation, since it is a network application and the copyleft obligation reaches the source of a modified version; that you understand the FTS5 build tag, since the Go binary is compiled with it and a build without it will not have the search the feature list promises; and that you accept the maintenance posture, because the project says the author may not actively review pull requests or respond to issues due to time constraints.

## FAQ

### What is Zen and how are notes stored?

Zen is a self-hosted notes application that ships as a single Go binary or a Docker Compose stack, with notes kept as standard Markdown files in a local SQLite database. It is designed for low resource usage and a minimal dependency footprint.

### What search does Zen provide?

Full-text search with BM25 ranking. The Go binary is compiled with the fts5 build tag for the SQLite full-text search extension, and there is also an experimental semantic search and similar images feature provided by a separate project called Zen Intelligence.

### What can the Zen MCP server do?

It is listed among the experimental features and provides the ability to search, list and read notes, which means another tool can query your notes programmatically rather than through the application interface.

### How do I build and run Zen?

Run `make build` to build it from source, and `make dev` to run the application with the default configuration. The watch mode needs air and esbuild installed, and the Docker image builds the front end with esbuild and the server with CGO enabled and the fts5 build tag.

## Sources

- [Issues](https://github.com/sheshbabu/zen/issues)
- [License: AGPL-3.0](https://github.com/sheshbabu/zen/blob/master/LICENSE)
- [Project website](https://www.sheshbabu.com/zen/)
- [README](https://github.com/sheshbabu/zen/blob/master/README.md)
- [sheshbabu/zen on GitHub](https://github.com/sheshbabu/zen)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/sheshbabu-zen
