MCPcopy Index your code
hub / github.com/Mooncake-Labs/moonlink

github.com/Mooncake-Labs/moonlink @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
3,126 symbols 14,603 edges 317 files 975 documented · 31%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Moonlink 🥮

managed ingestion engine for Apache Iceberg

License Slack Twitter Docs

Overview

Moonlink is an Iceberg-native ingestion engine bringing streaming inserts and upserts to your lakehouse.

Ingest Postgres CDC, event streams (Kafka), and OTEL into Iceberg without complex maintenance and compaction.

Moonlink buffers, caches, and indexes data so Iceberg tables stay read-optimized.


             ┌──────────moonlink───────────┐                         
             │  ┌───────────────────────┐  │  ┌───────Iceberg───────┐
             │  │                       │  │  │      obj. store     │
Postgres ───►│  │┌ ─ ─ ─ ─ ┐ ┌ ─ ─ ─ ─ ┐│  │  │┌───────┐ ┌─────────┐│
             │  │                       │  │  ││       │ │         ││
Kafka    ───►│  ││  index  │ │  cache  ││  ├──►│ index │ │ parquet ││
             │  │                       │  │  ││       │ │         ││
Events   ───►│  │└ ─ ─ ─ ─ ┘ └ ─ ─ ─ ─ ┘│  │  │└───────┘ └─────────┘│
             │  │                  nvme │  │  │                     │
             │  └───────────────────────┘  │  └─────────────────────┘
             └─────────────────────────────┘                         

Note: Moonlink is in preview. Expect changes. Join our Community to stay updated!

Why Moonlink?

Traditional ingestion tools write data and metadata files per update into Iceberg. That's fine for slow-changing data, but on real-time streams it causes:

  • Tiny data files — frequent commits create thousands of small Parquet files
  • Metadata explosion — equality-deletes compound this problem

which leads to: - Slow read performance — query planning overhead scales with file count - Manual maintenance — periodic Spark jobs for compaction/cleanup

Moonlink minimizes write amplification and metadata churn by buffering incoming data, building indexes and caches on NVMe, and committing read-optimized files and deletion vectors to Iceberg.

Inserts are buffered and flushed as size-tuned Parquet

          ┌───moonlink───┐  ┌────iceberg───┐
          │┌─ ─ ─ ─ ─ ─ ┐│  │┌─ ─ ─ ─ ─ ─ ┐│
raw insert│              │  │              │
────────► ││   Arrow    │├─►││   Parquet  ││
          │              │  │              │
          │└─ ─ ─ ─ ─ ─ ┘│  │└─ ─ ─ ─ ─ ─ ┘│
          └──────────────┘  └──────────────┘

Deletes are mapped to deletion vectors using an index built on row positions

           ┌───moonlink───┐   ┌────iceberg───┐
           │┌─ ─ ─── ─ ─ ┐│   │┌─ ─ ─ ─ ─ ─ ┐│
raw deletes│              │   │              │
  ────────►││   index    │├──►││  deletion  ││
           │              │   │   vectors    │
           │└─ ─ ─── ─ ─ ┘│   │└─ ─ ─ ─ ─ ─ ┘│
           └──────────────┘   └──────────────┘

Write Paths

Moonlink supports multiple input sources for ingest:

  1. PostgreSQL CDC — ingest via logical replication with millisecond-level latency
  2. REST API — simple HTTP endpoint for direct event ingestion
  3. Kafka — sink support coming soon
  4. OTEL — sink support on the roadmap

Read Path

Moonlink commits data as Iceberg v3 tables with deletion vectors. These tables can be queried from any Iceberg-compatible engine.

Engines 1. DuckDB
2. Apache Spark 3. Postgres with pg_duckdb or pg_mooncake

Catalogs 1. AWS Glue — coming soon
2. Unity Catalog — coming soon


Real-Time Reads (<s freshness)

For workloads requiring sub-second visibility into new data, Moonlink supports real-time querying:

  1. DuckDB — with the duckdb_mooncake extension.
  2. Postgres — with the pg_mooncake extension.
  3. DataFusion – with Moonlink Datafusion

Quick Start

1. Clone & Build

Clone the repository and build the service binary:

git clone https://github.com/Mooncake-Labs/moonlink.git
cd moonlink
cargo build --release --bin moonlink_service

2. Start the Moonlink Service

Start the Moonlink service, which will store data in the ./data directory:

./target/release/moonlink_service ./data

3. Verify Service Health

Check that the service is running properly:

curl http://localhost:3030/health

4. Create a Table

Create a table with a defined schema. Here's an example creating a users table:

curl -X POST http://localhost:3030/tables/users \
  -H "Content-Type: application/json" \
  -d '{
    "database": "my_database",
    "table": "users",
    "schema": [
      {"name": "id", "data_type": "int32", "nullable": false},
      {"name": "name", "data_type": "string", "nullable": false},
      {"name": "email", "data_type": "string", "nullable": true},
      {"name": "age", "data_type": "int32", "nullable": true},
      {"name": "created_at", "data_type": "date32", "nullable": true}
    ],
    "table_config": {"mooncake": {"append_only": true}}
  }'

5. Insert Data

Insert data into the created table:

curl -X POST http://localhost:3030/ingest/users \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "insert",
    "request_mode": "async",
    "data": {
      "id": 1,
      "name": "Alice Johnson",
      "email": "alice@example.com",
      "age": 30,
      "created_at": "2024-01-01"
    }
  }'

Roadmap and Contributing

Roadmap (near‑term): 1. Kafka sink preview 2. Schema evolution from Postgres and Kafka 3. Catalog integrations (AWS Glue, Unity Catalog) 4. REST API stabilization (Insert, Upsert into Iceberg directly)

We’re grateful for our contributors. If you'd like to help improve Moonlink, join our community.

🥮

Extension points exported contracts — how you extend this code

BaseLatencyExporter (Interface)
An interface to export latency. [3 implementers]
src/moonlink/src/observability/latency_exporter.rs
HasAttributes (Interface)
A helper trait so we can unify NumberDataPoint and HistogramDataPoint. [2 implementers]
src/moonlink_service/src/otel/metrics_handler.rs
MetadataStoreTrait (Interface)
(no doc) [2 implementers]
src/moonlink_metadata_store/src/base_metadata_store.rs
PuffinWrite (Interface)
(no doc) [3 implementers]
src/moonlink/src/storage/table/iceberg/moonlink_catalog.rs
SchemaUpdate (Interface)
(no doc) [3 implementers]
src/moonlink/src/storage/table/iceberg/moonlink_catalog.rs
CatalogAccess (Interface)
(no doc) [3 implementers]
src/moonlink/src/storage/table/iceberg/moonlink_catalog.rs
TableManager (Interface)
(no doc) [2 implementers]
src/moonlink/src/storage/table/common/table_manager.rs

Core symbols most depended-on inside this repo

clone
called by 1980
src/moonlink/src/storage/mooncake_table/table_snapshot.rs
len
called by 353
src/moonlink/src/row/column_array_builder.rs
map
called by 267
src/moonlink/src/storage/table/iceberg/parquet_utils.rs
push
called by 234
src/moonlink/src/storage/wal.rs
commit
called by 232
src/moonlink/src/storage/mooncake_table.rs
send
called by 172
src/moonlink_connectors/src/pg_replicate/initial_copy_writer.rs
append
called by 169
src/moonlink/src/storage/mooncake_table/mem_slice.rs
push
called by 168
src/moonlink/src/storage/mooncake_table/shared_array.rs

Shape

Function 1,486
Method 1,231
Class 317
Enum 78
Interface 14

Languages

Rust100%

Modules by API surface

src/moonlink/src/storage/table/iceberg/tests.rs90 symbols
src/moonlink/src/storage/mooncake_table.rs71 symbols
src/moonlink/src/table_handler/chaos_test.rs65 symbols
src/moonlink/src/storage/table/iceberg/state_tests.rs62 symbols
src/moonlink/src/storage/wal.rs60 symbols
src/moonlink/src/table_handler/tests.rs53 symbols
src/moonlink_connectors/src/rest_ingest/json_converter.rs49 symbols
src/moonlink_service/src/rest_api.rs45 symbols
src/moonlink/src/storage/mooncake_table/tests.rs44 symbols
src/moonlink/src/storage/index/persisted_bucket_hash_map.rs42 symbols
src/moonlink_connectors/src/pg_replicate/postgres_source.rs41 symbols
src/moonlink/src/storage/mooncake_table/data_file_state_tests.rs41 symbols

Datastores touched

postgresDatabase · 1 repos

For agents

$ claude mcp add moonlink \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact