System Architecture Overview
Relevant source files
The following files were used as context for generating this wiki page:Umami is a privacy-focused web analytics application built with a modern, full-stack JavaScript architecture. The system is designed to be self-hosted and provides a fast and simple alternative to commercial analytics platforms. Its architecture revolves around a Next.js application that serves both the user-facing dashboard and the data collection API, with PostgreSQL as the primary data store.
The core components include a lightweight tracking script for data collection, a Next.js backend for data processing and API services, and a React-based frontend for data visualization and reporting. The system is designed for scalability and flexibility, with support for Docker-based deployments and optional integrations with high-performance databases like ClickHouse.
Core Technologies & Dependencies
The project leverages a range of modern technologies to deliver its functionality. The primary dependencies and tools are defined in the package.json file.
| Technology/Library | Role | Description |
|---|---|---|
| Node.js | Runtime | The server-side JavaScript runtime environment. Requires v18.18+. |
| Next.js | Framework | The primary application framework for both the frontend (React) and backend (API routes). |
| React | UI Library | Used to build the user interface and dashboard components. |
| PostgreSQL | Database | The main relational database for storing all application data. Requires v12.14+. |
| Prisma | ORM | Used as the Object-Relational Mapper to interact with the PostgreSQL database. |
| ClickHouse | Database | An optional columnar database, with a client library included for high-performance analytics queries. |
| Redis | In-memory Store | A client library is included, suggesting its use for caching or other in-memory tasks. |
| pnpm | Package Manager | Used for managing project dependencies and running scripts. |
Sources: README.md:19-21, package.json:62,68,70,77,78
High-Level Architecture
The Umami system can be broken down into three main parts: the tracking client, the application server, and the data persistence layer.
This diagram shows the general flow of data from a user on a monitored website to the Umami backend and database, as well as an admin user viewing the analytics dashboard.
Sources: README.md, src/app/(main)/console/[websiteId]/TestConsolePage.tsx, src/app/api/links/route.ts
Application Components
Frontend Application (Next.js & React)
The frontend is a single-page application built using Next.js and React.
- Root Layout: The main HTML document structure is defined in
src/app/layout.tsx. It sets up the<html>and<body>tags, includes global stylesheets, and wraps the application in providers. - Application Shell: The core application UI is managed by
src/app/(main)/App.tsx. This component handles the main layout (including the side and mobile navigation), checks user authentication status via theuseLoginQueryhook, and renders the page content. - UI Components: The UI is constructed using the
@umami/react-zencomponent library, providing a consistent look and feel across the application. - Client-Side Routing: Next.js handles routing, with pages and layouts defined by the directory structure within
src/app.
Sources: src/app/layout.tsx, src/app/(main)/App.tsx, package.json:71
Backend API (Next.js API Routes)
The backend logic is implemented using Next.js API Routes (Route Handlers). These serverless functions handle incoming requests for data collection, authentication, and data retrieval for the dashboard.
- Endpoint Definition: API endpoints are created as files within the
src/app/api/directory, such assrc/app/api/links/route.ts. - Data Validation: Payloads are validated using
zod, as seen in thePOSThandler for/api/links. - Database Interaction: The API routes use Prisma to communicate with the database for creating, reading, updating, and deleting records.
- Permissions: The backend enforces permissions, checking if a user is authorized to perform an action before executing it.
Sources: src/app/api/links/route.ts:1-51
Data Collection (Tracking Script)
Data is collected from monitored websites using a lightweight JavaScript snippet.
- Loading the Script: The script is added to a website using a
<script>tag, as demonstrated inTestConsolePage.tsx. It is configured with adata-website-idto associate tracking data with the correct site. - Global Object: The script exposes a
window.umamiobject with methods for tracking. - Tracking Methods:
window.umami.track(): Used to track page views and custom events. It can be called with a simple event name or with a payload of structured data.window.umami.identify(): Used to associate tracking data with specific user properties.
The following is an example of how the tracking script is used to send various types of events:
// src/app/(main)/console/[websiteId]/TestConsolePage.tsx:18-42
function handleRunScript() {
window.umami.track(props => ({
...props,
url: '/page-view',
referrer: 'https://www.google.com',
}));
window.umami.track('track-event-no-data');
window.umami.track('track-event-with-data', {
test: 'test-data',
boolean: true,
//...
});
}
Sources: src/app/(main)/console/[websiteId]/TestConsolePage.tsx:18-42, 115-120
Data Layer
PostgreSQL Database
PostgreSQL is the primary database for the application. It stores core data including:
- Users, teams, and roles
- Websites and their configurations
- Analytics data such as page views, events, and sessions
The system requires PostgreSQL version 12.14 or higher. The connection is configured via the DATABASE_URL environment variable.
Sources: README.md:20, scripts/check-db.js:15, package.json:77
Database Management & Migration
Database health checks and migrations are handled by scripts. The check-db.js script performs several key functions upon application startup.
This flow ensures the database is properly configured, accessible, and up-to-date before the application starts.
Sources: scripts/check-db.js:8, 55-76
Optional Components: ClickHouse & Redis
The package.json file includes client libraries for ClickHouse (@clickhouse/client) and Redis (@umami/redis-client). This indicates that while PostgreSQL is the primary store, Umami can be configured to leverage these services for specific purposes, likely:
- ClickHouse: A high-performance, column-oriented database ideal for running fast analytical queries on large event datasets.
- Redis: An in-memory data store, likely used for caching, session management, or queueing to improve performance and scalability.
Sources: package.json:62, 70
Build and Deployment
Build Process
The application build is orchestrated by the build script in package.json. It runs a sequence of tasks to prepare all parts of the application.
This diagram illustrates the steps in the build process, from environment checks to building the final Next.js application.
Sources: package.json:11
Deployment Options
Umami offers multiple deployment strategies:
- From Source: The application can be built and run directly from the source code using
pnpmcommands.pnpm installpnpm run buildpnpm run start
- Docker: For containerized environments, a
docker-compose.ymlfile is provided to run Umami along with a PostgreSQL database.docker compose up -d
By default, the application starts on http://localhost:3000.
Sources: README.md:24-57
Key Data Flows
Event Tracking Flow
This sequence diagram shows how an event from a monitored website is captured and stored.
User Authentication Flow
The application secures the dashboard by requiring users to log in.
- A user attempts to access a protected page.
- The
App.tsxcomponent uses theuseLoginQueryhook to check for a valid session. - If the user is not authenticated (
erroris returned from the query), the application redirects to the login page. - Upon successful login, an authentication token is stored (referenced by the constant
AUTH_TOKEN). Subsequent requests to the API include this token for authorization.
Sources: src/app/(main)/App.tsx:19, 29-34, src/lib/constants.ts:2
Summary
The Umami system architecture is a well-defined, modern web application stack. It uses Next.js to efficiently serve both the user-facing dashboard and the backend API. The reliance on PostgreSQL with Prisma provides a stable and maintainable data layer, while the inclusion of optional components like ClickHouse and Redis allows for enhanced performance and scalability. The clear separation between the data collection script, the processing backend, and the presentation frontend results in a robust and extensible analytics platform.