Skip to main content

Overview

Lichess consists of two main build systems:
  1. Scala backend: Built with sbt (Scala Build Tool)
  2. TypeScript frontend: Built with a custom build system based on esbuild
This guide covers compilation, packaging, and deployment builds.

Building the Backend

sbt Console

The primary interface for building the Scala backend is the sbt console.

Starting sbt

This wrapper script:
  • Validates Java installation
  • Creates default config files if missing
  • Launches sbt with configured JVM options
The .sbtopts file configures JVM memory:
  • -J-Xms2g: Initial heap size (2GB)
  • -J-Xmx8g: Maximum heap size (8GB)
  • -J-Xss2m: Thread stack size (2MB)

Common sbt Commands

Module-Specific Builds

Compile specific modules:

Compilation Order

The build.sbt defines module dependencies. sbt compiles modules in order:
  1. Level 1: core, coreI18n
  2. Level 2: ui, common, tree
  3. Level 3: db, room, search
  4. Level 4: memo, rating
  5. Level 5+: Feature modules (game, user, tournament, etc.)
See the Module Structure for the complete dependency graph.

Incremental Compilation

sbt uses incremental compilation:
  • Only changed files are recompiled
  • Dependent modules are recompiled if needed
  • Compilation state is cached

Production Packaging

Create a production distribution:
This creates a zip file in target/universal/ containing:
  • Compiled classes
  • Dependencies
  • Startup scripts
  • Configuration

Building the Frontend

Build Script

The ui/build script handles all frontend compilation:

Build Options

Building Specific Packages

Build only specific UI packages:

Build Process

The build script performs these steps:

Build Output

Build artifacts are written to:

Watch Mode

In watch mode, the build system:
  1. Monitors source files for changes
  2. Rebuilds affected packages incrementally
  3. Updates the manifest
  4. Prints success/error messages
Example output:

Full Build

To build everything from scratch:

Development Build Workflow

For active development:

Internationalization Build

Translations are compiled during the sbt build:
Translation files in translation/source/ are serialized to binary format.

Optimization

Backend Optimization

sbt uses:
  • Incremental compilation: Only changed files
  • Parallel compilation: Multiple modules at once (when possible)
  • Dependency caching: Downloaded dependencies cached locally

Frontend Optimization

esbuild provides:
  • Fast bundling: Written in Go, highly parallelized
  • Tree shaking: Removes unused code
  • Minification: Smaller file sizes (production mode)
  • Code splitting: Shared chunks across modules
  • Source maps: For debugging (development mode)

Production Optimizations

Production mode enables:
  • Minification
  • Dead code elimination
  • Optimized chunk splitting
  • Smaller source maps (or none)

Build Performance

Improving sbt Performance

  1. Allocate more memory in .sbtopts:
  2. Use sbt server: Keep sbt running, don’t restart
  3. Build specific modules:

Improving UI Build Performance

  1. Build specific packages:
  2. Use watch mode: Incremental rebuilds are faster
  3. Upgrade Node.js: Newer versions are faster

CI/CD Builds

GitHub Actions builds Lichess on every commit:
See .github/workflows/ for the complete CI configuration.

Troubleshooting

sbt Out of Memory

Increase heap size in .sbtopts:

UI Build Fails

Compilation Errors

Slow Builds

  • Check system resources (CPU, RAM)
  • Close other applications
  • Use module-specific builds
  • Keep sbt running (don’t restart)

Next Steps

Additional Resources