PGN Merger

Active CLI Tools
A zero-dependency CLI to merge hundreds of chess PGN files in seconds.

Merge multiple chess PGN files into one database with this fast F# CLI. Zero dependencies, streaming I/O, preserves all game metadata.

Built with F#.NET 10

PGN Merger: Merge Chess PGN Files from the Command Line#

A fast, standalone command-line tool to merge multiple PGN (Portable Game Notation) chess files into a single database. Written in F# with streaming I/O, it handles thousands of files with ~64 KB of memory.

When I needed to aggregate Lichess Elite PGN files for opening preparation, existing tools either required Python dependencies, discarded game metadata, or forced games into variation trees. I wanted something simpler: a zero-dependency CLI that takes a folder of .pgn files and produces one clean merge.pgn.

Quick Start#

Terminal window
# Install from NuGet (requires .NET 10.0 SDK)
dotnet tool install --global PgnMerger
# Merge all PGN files in a folder
pgn-merger ./lichess_games

The tool creates merge.pgn in the target folder. Done.

What Is a PGN File?#

PGN (Portable Game Notation) is the standard text format for recording chess games. Every game includes headers (player names, event, date, result) and the move list. When you download games from Lichess or Chess.com, you get .pgn files, often hundreds or thousands of them. Merging PGN files into one database makes analysis and opening preparation far easier — load a single file into Scid vs PC, ChessBase, or your engine of choice.

Features#

  • Merge entire directories — point at a folder, get a single merge.pgn
  • Preserves all metadata — headers, comments, NAGs, and variations stay intact
  • Zero dependencies — standalone binary, no Python or runtime required
  • Cross-platform — runs on Windows, macOS, and Linux via .NET
  • Memory-efficient — streaming I/O with fixed 64 KB buffers, regardless of file size
  • Recursive mode — include subdirectories with --recursive
  • Progress feedback — optional verbose mode shows throughput per file
  • Safe by default — handles missing directories, permission errors, and excludes the output file from input

Installation#

Install as a .NET global tool:

Terminal window
dotnet tool install --global PgnMerger

Or add the NuGet package to your project.

From Source#

Requires .NET 10.0 SDK:

Terminal window
git clone https://github.com/CorentinGS/pgn-merger.git
cd pgn-merger
dotnet build

Usage#

Terminal window
# Basic: merge all PGN files in a folder
pgn-merger ./lichess_games
# With verbose output
pgn-merger ./lichess_games --verbose
# Custom output filename
pgn-merger ./lichess_games --output my_database.pgn
# Include subdirectories recursively
pgn-merger ./lichess_games --recursive

The tool creates merge.pgn (or your chosen filename) in the target folder. Exit code 0 means success, 1 means complete failure, 2 means partial success (some files failed).

How PGN Merger Compares to Alternatives#

ToolLanguageStandalonePreserves HeadersPreserves CommentsMerge Type
PGN MergerF# / .NETYesYesYesClean concatenation
merge-pgnPythonNo (requires python-chess)NoNoVariation tree
pgn-toolsPythonNo (requires python-chess)YesYesVariation tree

PGN Merger is the only tool that does just concatenation: no parsing, no transformation, no dependencies. This makes it faster and safer for simple aggregation tasks.

FAQ#

How do I merge Lichess PGN files?#

Download your games from Lichess (Settings → Export games), place all .pgn files in one folder, then run pgn-merger ./your_folder. The tool preserves all Lichess metadata including ratings, timestamps, and opening codes (ECO).

Can I merge PGN files from Chess.com?#

Yes. Export your games from Chess.com in PGN format and use the same process. The tool handles any valid PGN file regardless of source — Lichess, Chess.com, ICC, or custom databases.

Does PGN Merger modify game data?#

No. PGN Merger performs a byte-for-byte append operation. It does not parse, validate, or transform the games in any way. What goes in is exactly what comes out.

How do I merge PGN files recursively (with subdirectories)?#

Use the --recursive flag:

Terminal window
pgn-merger ./chess_database --recursive

This walks all subdirectories and merges every .pgn file found.

How much memory does PGN Merger use?#

Approximately 64 KB per file. The tool streams data through fixed-size buffers and never loads entire files into memory. You can merge a 50 GB PGN archive on a machine with 512 MB of RAM.

What is the difference between merging and combining PGN files?#

“Merging” in chess software often means building a variation tree or database with deduplication. PGN Merger does concatenation: it appends files sequentially, preserving each game as-is. This is ideal for building raw databases for analysis engines.

Technical Details#

  • Language: F# 7.0
  • Runtime: .NET 10.0
  • Input: Any valid PGN files (UTF-8)
  • Output: Single concatenated PGN file
  • Memory usage: ~64 KB per file (fixed buffer)
  • Exit codes: 0 (success), 1 (complete failure), 2 (partial success)

Want to understand the implementation? I wrote a detailed technical walkthrough covering the streaming I/O, functional patterns, and performance optimizations behind PGN Merger.

Looking for a Go-based chess library? Check out my corentings/chess project — move generation, PGN encoding, and UCI interop, all in Go.

Get the Source#

PGN Merger is open source under the MIT license.

View on GitHub · Install from NuGet · Report an issue