Gotify
Audited from github.com/gotify/server
Gotify is a self-hosted, lightweight push-notification server: a Go REST and WebSocket backend paired with a React and TypeScript web UI, used to send and receive real-time messages from scripts, CI jobs and other services.
- Language
- Go
- Database
- SQLite
- Hosting
- Docker
- Running for
- 5 years
- Team
- 2-5 People
Why this architecture
Gotify keeps the server one deployable Go binary by embedding its Vite/React web UI, using Gin and gorilla/websocket for the REST and streaming API, and swapping SQLite, MySQL or PostgreSQL through GORM, while a compiled Go plugin system handles extensibility instead of a scripting layer.
Tech stack by layer
10 technologies · audited Sep 17, 2026- ReactWeb UI (ui/) built with React 19 and TypeScript, compiled by Vite and served by the Go backend.
- MobXClient-side state management for the web UI (mobx, mobx-react-lite, mobx-utils).
- Material UIComponent library for the web UI (@mui/material, @mui/icons-material) styled with Emotion.
- ViteDev server, build and Vitest-based test runner for the ui/ package.
- GoEntire server (REST API, WebSocket stream, auth, plugin host) is the Go module github.com/gotify/server/v3.
- GinHTTP framework for the REST API, with gin-contrib/cors and gin-contrib/gzip middleware.
- WebSocketsgorilla/websocket streams new messages to connected clients in real time via api/stream.
- Zitadel OIDCzitadel/oidc/v3 implements OpenID Connect login (api/oidc.go) alongside built-in username/password auth.
- GORMORM abstracting the database layer; database/*.go implements applications, clients, messages and users on top of it.
- SQLiteOne of three GORM-driven database backends (gorm.io/driver/sqlite), commonly used for small self-hosted instances.
- MySQLAlternative GORM database backend (gorm.io/driver/mysql) for larger or shared deployments.
- PostgreSQLAlternative GORM database backend (gorm.io/driver/postgres).
- DockerMulti-stage build (docker/Dockerfile): node:24 compiles the UI, a gotify/build image compiles Go, debian runs the result.
- GitHub Actionsbuild.yml is the CI workflow (referenced by the README build-status badge).
- VitestFrontend unit tests for the ui/ package (yarn test / CI=true GOTIFY_EXE=... yarn test in the Makefile).
- golangci-lintGo linting configured via .golangci.yml, run through the Makefile check-go target.
Gotify architecture diagram
Open SVGDiagram as text
- Senders (scripts · apps · REST) → gotify server (Go · Gin): POST message
- Web UI (React · MobX · MUI) → gotify server (Go · Gin): REST
- Subscribers (Android · CLI (separate repos)) → Message stream (WebSocket): WebSocket
- Web UI (React · MobX · MUI) → Message stream (WebSocket): WebSocket
- gotify server (Go · Gin) → Message stream (WebSocket): push
- gotify server (Go · Gin) → Database (SQLite / MySQL / Postgres (GORM)): GORM
- gotify server (Go · Gin) → Plugins (compiled Go plugins): load
- gotify server (Go · Gin) → OIDC provider (Zitadel OIDC): login
Key architectural decisions
7 decisions- 01
Delivery is push over WebSocket, not polling, with a REST API alongside it
api/stream implements a gorilla/websocket endpoint that pushes new messages to connected clients immediately, while api/message.go, api/application.go, api/client.go and api/user.go expose a conventional Gin-based REST API for everything else (creating apps, clients, managing messages).
- 02
The database backend is swappable through GORM, not hard-coded
go.mod pulls in gorm.io/driver/mysql, gorm.io/driver/postgres and gorm.io/driver/sqlite behind the shared gorm.io/gorm ORM, and database/database.go selects between them at startup, so a Gotify instance can run on an embedded SQLite file or a shared MySQL/PostgreSQL server without code changes.
- 03
Extensibility is a compiled Go plugin system, not a scripting layer
plugin/manager.go loads compiled Go plugins (.so files) at runtime against the gotify/plugin-api contract declared in go.mod, with plugin/example and plugin/compat covering the plugin API surface and cross-version compatibility, rather than embedding a scripting language like Lua or JavaScript for extensions.
- 04
OIDC login sits next to built-in username/password auth
api/oidc.go and go.mod's zitadel/oidc/v3 dependency add OpenID Connect login as an alternative to the default local-account flow implemented in auth/authentication.go and auth/token.go, letting self-hosters attach an existing identity provider without replacing the built-in auth.
- 05
The web UI is a separate Vite/React app the Go binary serves, not server-rendered
ui/package.json defines an independent Vite + React 19 + TypeScript single-page app (with its own vitest suite and ESLint config); ui/serve.go embeds the built assets into the Go binary so a Gotify deployment is still one process, and the Dockerfile's BUILD_JS argument controls whether that UI build runs as part of the image build.
- 06
Docker images are cross-compiled for five architectures from one Makefile target
The build-docker-multiarch target in the Makefile drives docker buildx build --platform linux/amd64,linux/arm64,linux/386,linux/arm/v7,linux/riscv64, tagging both gotify/server and ghcr.io/gotify/server per architecture, so the same Dockerfile produces images for common self-hosting targets including Raspberry Pi (arm) and RISC-V boards.
- 07
Companion CLI and Android clients live outside this repository
The README points to gotify/cli and gotify/android as separate repositories rather than folding them into this monorepo, keeping the server repository scoped to the API, WebSocket stream, web UI and plugin host.
How Gotify is built
How Gotify is structured
Gotify is a single Go module, github.com/gotify/server/v3 (go.mod), with an embedded frontend rather than a monorepo of separately deployed services. The backend is organized into small, focused packages: api (Gin route handlers for applications, clients, messages, sessions, tokens, users and the OIDC flow), auth (authentication, cookies, CORS, tokens), config (YAML/env configuration and migration), database (GORM models and queries), model (shared API/DB types), plugin (the compiled-plugin host), router (route wiring) and runner (process startup). The ui/ directory is an independent React + TypeScript single-page app with its own package.json, build tooling and tests, whose compiled output ui/serve.go embeds into the final Go binary.
Frontend
ui/package.json defines a Vite-built React 19 application in TypeScript. State management uses MobX (mobx, mobx-react-lite, mobx-utils) rather than Redux or React Context alone, and the component layer is Material UI (@mui/material, @mui/icons-material) styled with Emotion and tss-react. Data fetching goes through axios; react-router (v8) handles client-side navigation; react-virtuoso virtualizes long message lists; @dnd-kit provides drag-and-drop (for reordering, based on the fractional-indexing/fracdex dependency shared with the Go backend's fracdex package); and @uiw/react-codemirror plus react-markdown/remark-gfm support Markdown message rendering. Tests run on Vitest, and linting on ESLint with a flat config (ui/eslint.config.mjs).
Backend & APIs
The REST API is built on Gin (gin-gonic/gin), with gin-contrib/cors and gin-contrib/gzip as middleware; go-playground/validator/v10 validates request payloads. Real-time delivery runs separately through api/stream, a gorilla/websocket endpoint that pushes newly created messages to connected clients without polling. Authentication supports both a built-in username/password flow (auth/authentication.go, auth/token.go, auth/cookie.go) and OpenID Connect via zitadel/oidc/v3 (api/oidc.go), so an instance can delegate login to an external identity provider. API documentation is generated with go-swagger into docs/spec.json, served through docs/ui.go and kept in sync by the Makefile's check-swagger target, which fails CI if the generated spec drifts from the code.
Data & persistence
database/database.go and the surrounding database/*.go files implement applications, clients, messages, users and plugin storage on top of gorm.io/gorm. Three database drivers are available through GORM: gorm.io/driver/sqlite (a common default for small self-hosted setups), gorm.io/driver/mysql, and gorm.io/driver/postgres, letting an operator pick a backend appropriate to their deployment size without touching application code. config/migrate handles schema migrations between versions.
Build, test & deploy
CI is defined by .github/workflows/build.yml (referenced by the README's build-status badge); Go linting runs through golangci-lint per .golangci.yml, invoked via the Makefile's check-go target, while check-js runs the UI's own yarn lint and format checks. docker/Dockerfile is a three-stage build: a node:24 stage compiles the UI (gated by the BUILD_JS build arg), a gotify/build image (a project-maintained Go build image, versioned per Go release) compiles the server binary with CGO_ENABLED-style static linking, and a final debian stage runs the result with a curl-based HEALTHCHECK against /health. The Makefile's build-docker-multiarch target drives docker buildx build --platform linux/amd64,linux/arm64,linux/386,linux/arm/v7,linux/riscv64, publishing tagged images to both Docker Hub (gotify/server) and ghcr.io/gotify/server.
Self-hosting notes
Gotify is designed to be self-hosted as a single container or binary: gotify-server.env.example documents environment-based configuration, and the multiarch Docker build directly targets common self-hosting hardware, including ARM boards (arm-7, arm64) and RISC-V. Because the web UI is embedded in the Go binary via ui/serve.go, there is no separate frontend process to deploy or reverse-proxy independently. Database choice is the main scaling lever: the SQLite driver keeps a deployment to a single file with no external dependency, while the MySQL and PostgreSQL drivers support shared or higher-throughput setups. Companion clients — a CLI (gotify/cli) and an Android app (gotify/android) — are separate repositories the README links to rather than code in this one.
What to copy (and what not to)
Embedding a Vite-built SPA directly into the server binary (ui/serve.go) while keeping the frontend's package.json, dependencies and tests fully independent under ui/ is a clean split worth copying for small self-hosted tools: contributors can work on the UI with normal frontend tooling, while end users still get a single deployable artifact. The compiled-Go-plugin system (plugin/manager.go loading .so files against gotify/plugin-api) is a heavier design decision to copy carefully — Go plugins have known portability constraints (matching Go toolchain and OS/arch between host and plugin), so a project without Gotify's small, controlled plugin ecosystem might get more mileage from a subprocess- or WASM-based extension model instead.
Sources & repo audit
- Audited
- Sep 17, 2026
- Commit
- e6361ca
- License
- NOASSERTION
- go.mod (Gin, GORM, WebSocket, Zitadel OIDC dependencies)
- ui/package.json (React 19, MobX, MUI, Vite, Vitest)
- docker/Dockerfile (multi-stage node/go/debian build)
- Makefile (multiarch Docker build target)
Independent analysis of repository at github.com/gotify/server. Spotted an inaccuracy? Use the claim form to request a correction.
Show this stack on your README or website
[](https://stackitfast.com/project/gotify)Paste it into your README. It shows your current stack and links to this page.
Scaffold it with your agent
Paste this prompt into Claude Code, Cursor, Windsurf or AGY to start a project with Gotify's architecture.
- 1Copy the promptThe full markdown spec, with every layer and decision.
- 2Open your AI toolClaude Code, Cursor, Windsurf or Copilot, in a new repo.
- 3Paste and scaffoldUse it as the first instruction; review before you ship.
# MISSION: Scaffold "Gotify" Production Architecture
You are an expert Senior Staff Software Architect and Full-Stack Engineer. Your mission is to scaffold and implement a production-grade, highly reliable, and modular codebase following the proven architecture of **Gotify**.
---
## 1. PROJECT SPECIFICATIONS & BENCHMARK
- **Reference Architecture**: Gotify
- **What It Does**: Gotify is a self-hosted, lightweight push-notification server: a Go REST and WebSocket backend paired with a React and TypeScript web UI, used to send and receive real-time messages from scripts, CI jobs and other services.
- **Domain & Category**: Self-Hosted Real-Time Push Server
- **Production Scale**: 2-5 People
- **Development Mode**: CLASSIC
- **Architectural Rationale**: Gotify keeps the server one deployable Go binary by embedding its Vite/React web UI, using Gin and gorilla/websocket for the REST and streaming API, and swapping SQLite, MySQL or PostgreSQL through GORM, while a compiled Go plugin system handles extensibility instead of a scripting layer.
- **Live Website Reference**: https://gotify.net
- **Source Repository**: https://github.com/gotify/server
---
## 2. PRODUCTION TECH STACK
- **Full Stack Array**: Go, TypeScript, React, Gin, GORM, WebSockets, SQLite, MySQL, PostgreSQL, Docker
- **Primary Language(s)**: Go, TypeScript
- **License of the reference repo**: NOASSERTION
- **Frontend**: React — Web UI (ui/) built with React 19 and TypeScript, compiled by Vite and served by the Go backend.; MobX — Client-side state management for the web UI (mobx, mobx-react-lite, mobx-utils).; Material UI — Component library for the web UI (@mui/material, @mui/icons-material) styled with Emotion.; Vite — Dev server, build and Vitest-based test runner for the ui/ package.
- **Backend & APIs**: Go — Entire server (REST API, WebSocket stream, auth, plugin host) is the Go module github.com/gotify/server/v3.; Gin — HTTP framework for the REST API, with gin-contrib/cors and gin-contrib/gzip middleware.; WebSockets — gorilla/websocket streams new messages to connected clients in real time via api/stream.; Zitadel OIDC — zitadel/oidc/v3 implements OpenID Connect login (api/oidc.go) alongside built-in username/password auth.
- **Data & persistence**: GORM — ORM abstracting the database layer; database/*.go implements applications, clients, messages and users on top of it.; SQLite — One of three GORM-driven database backends (gorm.io/driver/sqlite), commonly used for small self-hosted instances.; MySQL — Alternative GORM database backend (gorm.io/driver/mysql) for larger or shared deployments.; PostgreSQL — Alternative GORM database backend (gorm.io/driver/postgres).
- **Infrastructure & deploy**: Docker — Multi-stage build (docker/Dockerfile): node:24 compiles the UI, a gotify/build image compiles Go, debian runs the result.; GitHub Actions — build.yml is the CI workflow (referenced by the README build-status badge).
- **Tooling, testing & ops**: Vitest — Frontend unit tests for the ui/ package (yarn test / CI=true GOTIFY_EXE=... yarn test in the Makefile).; golangci-lint — Go linting configured via .golangci.yml, run through the Makefile check-go target.
---
## 3. KEY ARCHITECTURAL DECISIONS (audited from https://github.com/gotify/server @ e6361ca)
1. **Delivery is push over WebSocket, not polling, with a REST API alongside it**: api/stream implements a gorilla/websocket endpoint that pushes new messages to connected clients immediately, while api/message.go, api/application.go, api/client.go and api/user.go expose a conventional Gin-based REST API for everything else (creating apps, clients, managing messages).
2. **The database backend is swappable through GORM, not hard-coded**: go.mod pulls in gorm.io/driver/mysql, gorm.io/driver/postgres and gorm.io/driver/sqlite behind the shared gorm.io/gorm ORM, and database/database.go selects between them at startup, so a Gotify instance can run on an embedded SQLite file or a shared MySQL/PostgreSQL server without code changes.
3. **Extensibility is a compiled Go plugin system, not a scripting layer**: plugin/manager.go loads compiled Go plugins (.so files) at runtime against the gotify/plugin-api contract declared in go.mod, with plugin/example and plugin/compat covering the plugin API surface and cross-version compatibility, rather than embedding a scripting language like Lua or JavaScript for extensions.
4. **OIDC login sits next to built-in username/password auth**: api/oidc.go and go.mod's zitadel/oidc/v3 dependency add OpenID Connect login as an alternative to the default local-account flow implemented in auth/authentication.go and auth/token.go, letting self-hosters attach an existing identity provider without replacing the built-in auth.
5. **The web UI is a separate Vite/React app the Go binary serves, not server-rendered**: ui/package.json defines an independent Vite + React 19 + TypeScript single-page app (with its own vitest suite and ESLint config); ui/serve.go embeds the built assets into the Go binary so a Gotify deployment is still one process, and the Dockerfile's BUILD_JS argument controls whether that UI build runs as part of the image build.
6. **Docker images are cross-compiled for five architectures from one Makefile target**: The build-docker-multiarch target in the Makefile drives docker buildx build --platform linux/amd64,linux/arm64,linux/386,linux/arm/v7,linux/riscv64, tagging both gotify/server and ghcr.io/gotify/server per architecture, so the same Dockerfile produces images for common self-hosting targets including Raspberry Pi (arm) and RISC-V boards.
7. **Companion CLI and Android clients live outside this repository**: The README points to gotify/cli and gotify/android as separate repositories rather than folding them into this monorepo, keeping the server repository scoped to the API, WebSocket stream, web UI and plugin host.
---
## 4. NON-NEGOTIABLE ARCHITECTURAL GUARDRAILS
1. **Monorepo & Modular Separation**:
- Structure as a Turborepo monorepo with strict package boundaries:
- `apps/web`: Application UI, routing, layouts, and server endpoints.
- `packages/ui`: Shared design tokens, CSS variables, and Radix UI primitive components.
- `packages/db`: Database schemas, client singleton, declarative migrations, and seed scripts.
- `packages/config`: Shared TypeScript, ESLint, and build configurations.
2. **Strict Type Safety & Zero `any` Policy**:
- Enable `strict: true`, `noImplicitAny: true`, and `strictNullChecks: true`.
- Validate ALL external inputs, API request bodies, and query parameters with **Zod** schemas before execution.
3. **Frontend & Rendering Guidelines**:
- Isolate interactive UI state to leaf components. Keep core pages lightweight and performant.
4. **Design System & Aesthetics**:
- Keep every color, radius, shadow and font in a single token file (CSS variables) and consume tokens everywhere; never hardcode hex values in components.
- Prefer crisp 1px borders and one subtle shadow scale over blurry default shadows. Pair one sans-serif for body/headings with one monospace for tags, badges, metrics, and code.
5. **Data Layer & Reliability**:
- Write declarative schema definitions with foreign keys, composite indexes on queried filters, and automated timestamp triggers.
- Use connection pooling and prepared statements for serverless database execution.
---
## 5. STEP-BY-STEP SCAFFOLDING ROADMAP
- **Phase 1: Workspace & Root Config**: Initialize package manager, monorepo configuration (`turbo.json`, `tsconfig.base.json`, `package.json`).
- **Phase 2: Database Schema & Client**: Set up the data layer (GORM, SQLite, MySQL, PostgreSQL): client, connection pool, models, and migration scripts.
- **Phase 3: Design Tokens & UI Primitives**: Build accessible `Button`, `Input`, `Card`, `Badge`, and layout wrappers inside `packages/ui`.
- **Phase 4: Core Application Routes & Handlers**: Implement primary authentication, user session handling, and application routes.
- **Phase 5: Quality Assurance & Build Verification**: Run `tsc --noEmit`, ESLint, Prettier, and smoke test suites to ensure zero compilation or runtime errors.
---
## 6. EXECUTION INSTRUCTIONS
1. Review all specifications, architectural guardrails, and stack choices above.
2. Present the full monorepo directory tree structure.
3. Systematically generate the complete, production-ready codebase according to the 5-phase roadmap above — starting with the root workspace setup, followed by the database schema, UI design system package, and full-stack application routes until the repository is fully scaffolded and ready to run.Copied 9 times · 5 of 5 reported launches succeeded (100%)
Frequently asked about Gotify
What is Gotify built with?
Gotify is a Go server (Gin for REST, gorilla/websocket for real-time push, GORM for the database layer) paired with a React 19 and TypeScript web UI built with Vite; the Go binary embeds and serves the compiled UI.
Does Gotify need a database?
Yes, but it is flexible: GORM drivers let Gotify run against SQLite, MySQL or PostgreSQL (gorm.io/driver/sqlite, /mysql, /postgres in go.mod), selected at configuration time rather than fixed in code.
Can I self-host Gotify?
Yes, self-hosting is the primary use case. docker/Dockerfile builds a multi-stage image, and the Makefile cross-compiles it for amd64, arm64, 386, arm/v7 and riscv64, covering common self-hosting hardware including Raspberry Pi.
How does Gotify deliver messages in real time?
Clients connect to a WebSocket endpoint (api/stream, built on gorilla/websocket) and receive new messages as they are created through the REST API, rather than polling for updates.
Does Gotify support plugins?
Yes. plugin/manager.go loads compiled Go plugins (.so files) implementing the gotify/plugin-api interface at runtime, so extensions are written in Go rather than an embedded scripting language.
One email a month: new deep dives and stack trends
New source-audited architectures, head-to-head comparisons and the monthly stack report. No spam, unsubscribe anytime.
Similar architectures
- Apache AnswerClassicQ&A & Developer Knowledge Community · 6-20 PeopleShares Go · Gin · TypeScript
- GiteaClassicLightweight Self-Hosted Git Service · 20+ peopleShares Go · TypeScript · SQLite
- PrismaClassicNext-Generation Node.js & TypeScript ORM · 1M+ MAUShares TypeScript · PostgreSQL · MySQL
- AutheliaClassicAuthentication & SSO Proxy Companion · 6-20 PeopleShares Go · React · TypeScript
- PocketBaseClassicEmbedded Backend · SoloShares Go · SQLite
- AtuinClassicShell History Sync · 2-5 peopleShares SQLite · PostgreSQL · MySQL