Skip to main content
The Oyasai Server Platform is a modern, reproducible infrastructure for running a Minecraft server built with Nix flakes, Gradle, and Kotlin. The platform emphasizes declarative configuration, reproducible builds, and modular plugin development.

Core Principles

The architecture is built on three foundational principles:
  1. Reproducibility: Every build is deterministic and reproducible through Nix
  2. Modularity: Plugins and packages are independently developed and composed
  3. Declarative Configuration: Infrastructure and dependencies declared as code

Technology Stack

Nix Flakes

Manages dependencies, builds, and deployment with reproducible guarantees

Gradle 9

Builds Kotlin plugins with dependency management and multi-project support

Kotlin 2.3

Primary language for plugin development on the JVM

Purpur 1.21.8

High-performance Minecraft server implementation

System Architecture

The platform follows a layered architecture:

Key Components

Flake Architecture

The root flake.nix orchestrates the entire build system:
{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
    gradle2nix.url = "github:oyasaiserver/gradle2nix?ref=v2";
    flake-parts.url = "github:hercules-ci/flake-parts";
    # ... additional inputs
  };
}
The flake imports modular Nix configurations:
  • nix/oyasai-scope.nix - Custom package scope and build logic
  • nix/devshells.nix - Development environment configuration
  • nix/docker.nix - Container image generation
  • nix/treefmt.nix - Code formatting rules

Oyasai Scope

The Oyasai scope (nix/oyasai-scope.nix) defines a custom package set with:
  • Java toolchain: Temurin JDK/JRE 25
  • Build tools: Gradle 9, gradle2nix
  • Plugin builders: Batch compilation of all plugins
  • Server packages: Multiple server configurations (main, minimal, marzipan)
  • Docker support: Layered image builder
The scope uses lib.makeScope to create an isolated package namespace, preventing conflicts with nixpkgs.

Plugin Build System

Plugins are built in batch mode for efficiency:
plugins-batch = scopeSelf.gradle2nix.buildGradlePackage {
  pname = "plugins";
  version = "0.0.0";
  src = /* filtered source tree */;
  gradleBuildFlags = [ "build" ];
  installPhase = ''
    mkdir -p $out
    cp plugins/*/build/libs/*.jar $out
  '';
};
Individual plugins are then extracted as separate derivations:
plugins = lib.mapAttrs' (name: _:
  lib.nameValuePair (lib.toLower name) (
    pkgs.runCommand name { } ''
      mkdir -p $out
      cp ${plugins-batch}/${name}.jar $out
    ''
  )
) (builtins.readDir ../plugins);

Build Pipeline

The build process follows this flow:
  1. Dependency Resolution: gradle2nix locks all Maven dependencies
  2. Plugin Compilation: All plugins built together via Gradle
  3. Server Assembly: Purpur server + plugins wrapped with runtime config
  4. Docker Packaging: Layered images built for deployment
1

Lock Dependencies

Run gradle2nix to generate gradle.lock from Gradle dependencies
2

Build Plugins

Nix builds all plugins in a hermetic environment using the lock file
3

Assemble Server

oyasaiPurpur function combines server JAR with selected plugins
4

Create Docker Image

Docker builder creates layered images with the server package

Package Outputs

The flake exposes these packages:
Production server with full plugin set including EssentialsX, LuckPerms, Vault, and custom plugins
Minimal server configuration for testing
Specialized server configuration for specific use cases
Centralized registry of third-party plugins with version management
Utility for pushing Docker images to registries

Development Environment

The development shell provides:
devshells.default = {
  packages = [
    nodejs    # Node.js 24 for tooling
    jdk       # Temurin JDK 25
    terraform # Infrastructure as code
    gradle    # Gradle 9 build tool
    gradle2nix-cli # Dependency locking
  ];
};
Enter the development environment:
nix develop

Docker Integration

Docker images are built with layering for efficient caching:
passthru.docker = oyasaiDockerTools.buildLayeredImage {
  inherit name;
  config.Cmd = [ "${lib.getExe final}" ];
};
Images are automatically generated for:
  • All server packages
  • MariaDB database
  • Backup utilities

Monorepo Structure

Explore the project layout and organization

Nix Flakes

Deep dive into the Nix flake system

Plugin System

Learn how plugins are developed and built

Build docs developers (and LLMs) love