Skip to main content

Overview

Lichess is built as a highly scalable, fully asynchronous chess server that handles millions of concurrent users. The architecture separates concerns across multiple layers and services, optimized for real-time gameplay and low latency. Lichess production server architecture

System Components

Core Application (lila)

The main Lichess server, known as lila (li[chess in sca]la), is built with:

Scala 3

Modern, type-safe functional programming language providing excellent concurrency support

Play Framework 2.8

Web application framework handling HTTP requests, routing, and MVC structure

Akka Streams

Reactive streams for handling asynchronous, non-blocking data flows

MacWire

Compile-time dependency injection for managing component wiring
The application entry point is lila.app.Lila:main, which bootstraps the Play server and initializes all modules.

Module Architecture

Lichess is organized into 83 modular components in the /modules directory, each with specific responsibilities:
Core modules providing base functionality:
  • core - Basic types and utilities
  • coreI18n - Internationalization core
  • ui - User interface components and templates
  • common - Shared utilities used across modules
  • tree - Chess game tree representation
  • db - Database access layer for MongoDB
  • room - Real-time room/channel management
  • search - Elasticsearch integration for game search
  • memo - Caching layer using Caffeine/Scaffeine
  • rating - ELO rating calculations
  • game - Game state and logic
  • user - User accounts and profiles
  • puzzle - Tactical puzzles
  • study - Shared analysis boards
  • analyse - Computer analysis integration
  • gathering - Base for tournaments and events
Higher-level features like:
  • tournament, swiss, simul - Competition formats
  • relay - Broadcast of live games
  • challenge - Challenge system
  • chat, msg - Communication
  • security, mod - Moderation and safety
  • And many more…
Module dependencies are carefully structured to prevent circular dependencies. The build.sbt file explicitly defines the dependency hierarchy.

Frontend Architecture

Client-Side Stack

TypeScript

Type-safe JavaScript for all client code

Snabbdom

Lightweight virtual DOM library for efficient UI updates

Sass

CSS preprocessing with variables and mixins

esbuild

Ultra-fast JavaScript bundler

UI Package Structure

The frontend is organized as a pnpm monorepo workspace in /ui:
ui/
├── analyse/      # Analysis board
├── site/         # Main site pages
├── puzzle/       # Puzzle trainer
├── tournament/   # Tournament pages
├── lib/          # Shared libraries
├── build         # Custom build script
└── .build/       # Build system source
Each package has:
  • package.json - Dependencies and build configuration
  • src/ - TypeScript source files
  • Custom build property defining bundle/sync/hash rules

Build System

The custom ui/build script:
  1. Bundles TypeScript modules with esbuild
  2. Generates content-hashed filenames for cache busting
  3. Creates manifest files listing asset URLs
  4. Syncs npm dependencies to /public/npm
  5. Watches for changes in development mode
# Watch mode rebuilds on file changes
ui/build -w
Assets are compiled to /public/compiled with 8-character content hashes in filenames.

Data Layer

MongoDB

Primary database storing:
  • 4.7+ billion games in compressed format
  • User profiles and preferences
  • Tournament and simul data
  • Studies and analysis annotations
  • Forum posts and messages
Lichess uses ReactiveMongo 1.1.0-RC20, a reactive, non-blocking MongoDB driver for Scala. Database queries are fully asynchronous using Scala Futures.

Redis

In-memory data store for:
  • WebSocket coordination between lila and lila-ws
  • Real-time pub/sub messaging
  • Session management
  • Rate limiting
  • Distributed locks
Uses Lettuce 7.5.0 as the Redis client.

Elasticsearch

Powers the game search engine, indexing:
  • Game metadata and results
  • Player information
  • Opening variations
  • Advanced query filters
Accessed via the lila-search client library.

Real-Time Communication

WebSocket Server (lila-ws)

A separate server handles all WebSocket connections:
  • Written in Scala
  • Optimized for connection handling
  • Communicates with main lila server via Redis pub/sub
  • Handles move broadcasts, chat, and live updates
In development, lila-ws runs on port 9664 by default. You need both servers running for full functionality.

Communication Flow

Browser ←→ lila-ws (WebSocket) ←→ Redis ←→ lila (HTTP)
  1. Client connects to lila-ws via WebSocket
  2. lila-ws subscribes to Redis channels
  3. lila publishes events to Redis
  4. lila-ws broadcasts to connected clients

Chess Engine Integration

Stockfish

The world’s strongest open-source chess engine:
  • Used for computer analysis
  • Evaluates positions and suggests best moves
  • Provides multi-PV (principal variation) analysis

Fishnet

Distributed computing network for analysis:
  • Community members donate CPU time
  • Client software available at lichess-org/fishnet
  • Analyzes games asynchronously
  • Results stored in evalCache module

Chess Logic

scalachess

Pure Scala chess library (separate repository):
  • Implements all chess rules and variants
  • Move validation and generation
  • Position representation
  • PGN parsing and export
  • Rating calculations
Version specified in project/Dependencies.scala:
object chess {
  val version = "17.15.3"
  val org = "com.github.lichess-org.scalachess"
  // Includes: core, testKit, playJson, rating, tiebreak
}

Request Handling

HTTP Flow

1

Nginx (Production)

Reverse proxy handling SSL termination and load balancing
2

Play Framework

Routes requests to appropriate controllers based on URL patterns
3

Controllers

Process requests, interact with modules, and return responses
4

Views

Rendered using scalatags - type-safe HTML generation in Scala

Asynchronous Execution

All I/O operations are non-blocking:
  • Database queries return Future[Result]
  • WebSocket messages use Akka Streams
  • HTTP calls use Play WS client
  • Rate limiting uses Redis Lua scripts
Lichess uses scala.concurrent.ExecutionContextOpportunistic as the default executor for better performance.

Caching Strategy

Multi-layer caching for optimal performance:

CDN

Cloudflare caches static assets globally with 1-year TTL

Application Cache

Caffeine/Scaffeine in-memory caches for frequently accessed data

Redis

Distributed cache shared across application instances
Content-hashed URLs (e.g., site.FE782A9C.js) ensure cache invalidation when files change.

Monitoring & Observability

Kamon

Integrated for metrics and monitoring:
  • System metrics (CPU, memory, GC)
  • Application metrics (request rates, latencies)
  • Custom business metrics
  • Exports to InfluxDB and Prometheus
Dependencies:
kamon.core        // 2.8.1
kamon.influxdb    // Metrics export
kamon.prometheus  // Prometheus integration

Security Features

Security Module

Handles:
  • Authentication and authorization
  • Password hashing with bcrypt
  • OAuth token management
  • Rate limiting per IP/user
  • Proxy/VPN detection using MaxMind and IP2Proxy
  • User-agent parsing for bot detection

Play Configuration

Security settings in conf/base.conf:
  • Session cookie configuration
  • CSRF protection
  • HTTP header limits
  • Request size limits

Deployment Architecture

Development Setup

  • Single machine running all components
  • MongoDB and Redis on localhost
  • lila on port 9663
  • lila-ws on port 9664

Production Setup

  • Multiple application servers
  • Separate database clusters
  • CDN for static assets
  • Load balancers
  • Monitoring infrastructure

Production Diagram

See the architecture diagram for production topology as of July 2022

Key Dependencies

  • Akka 2.6.21 - Actor system and streams
  • ReactiveMongo 1.1.0-RC20 - MongoDB driver
  • Lettuce 7.5.0 - Redis client
  • Caffeine 3.2.3 - High-performance caching
  • Play JSON 3.0.6 - JSON serialization
  • Kamon 2.8.1 - Metrics and monitoring
  • @lichess-org/chessground ^10.0.2 - Chessboard UI
  • @lichess-org/pgn-viewer ^2.5.9 - PGN viewer
  • chessops ^0.15 - Chess operations
  • snabbdom 3.5.1 - Virtual DOM
  • oxlint ^1.50.0 - Fast TypeScript linter
  • oxfmt ^0.35.0 - Code formatter
  • stylelint ^17.3.0 - CSS/Sass linter
  • scalafmt - Scala code formatting

Configuration Management

Configuration uses HOCON (Human-Optimized Config Object Notation):
conf/
├── base.conf                  # Base configuration
├── application.conf.default   # Default local config template
└── application.conf           # Your local overrides (gitignored)
Configuration is loaded hierarchically:
  1. base.conf - Shared defaults
  2. version - Version information
  3. application.conf - Local overrides

Browser Support

Lichess supports modern browsers:
BrowserVersionSupport Level
Firefox115+Full (recommended)
Chrome/Chromium112+Full
Edge109+Full
Safari13.1+Reasonable
Opera91+Reasonable
Older browsers are not supported. Modern JavaScript features (ES6+) and WebAssembly are required.

Performance Characteristics

Lichess architecture is optimized for:
  • High concurrency - Millions of concurrent connections
  • Low latency - Real-time move transmission under 100ms
  • Horizontal scalability - Stateless application servers
  • Efficient resource usage - Asynchronous I/O reduces thread overhead
  • Fast page loads - Content-hashed assets with aggressive caching
The fully asynchronous design using Scala Futures and Akka Streams allows handling massive traffic with relatively modest hardware.

Next Steps

Module Deep Dive

Explore individual modules in detail

API Reference

Learn about the HTTP API

Contributing

Start contributing to Lichess

lila-ws Repository

WebSocket server source code

Build docs developers (and LLMs) love