# MyDuck Server: a MySQL and Postgres speaking analytics server backed by DuckDB

> MyDuck Server is a Go server that stores data in DuckDB and speaks the MySQL and Postgres wire protocols, so an existing MySQL or Postgres client can run analytical queries against an OLAP engine, either as a replica of a primary database or as a standalone server.

**apecloud/myduckserver** — Unified MySQL, Postgres & FlightSQL Server, Powered by DuckDB.

- Repository: https://github.com/apecloud/myduckserver
- Website: https://myduck.io
- Stars: 594 · Forks: 47
- Language: Go
- License: Apache-2.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/apecloud-myduckserver

## The problem is that OLTP databases are poor at analytics

The README states the premise directly: MySQL and Postgres are the most popular open source databases for OLTP, but their performance in analytics often falls short, while DuckDB is built for fast embedded analytical processing. MyDuck Server is the join between the two, and the framing is careful. The project says MyDuck Server is not here to replace MySQL and Postgres, it is here to help MySQL and Postgres users do more with their data. The list of uses it gives covers the common asks: setting up an isolated, fast and real-time replica dedicated to ad-hoc analytics, batch jobs and LLM-generated queries without exhausting or corrupting the primary database, accelerating existing analytics with minimal changes, giving modern data tools richer connectivity, going beyond MySQL and Postgres syntax with DuckDB's advanced SQL, running DuckDB in server mode so a team can share an instance, and building HTAP systems by sending transactions to the primary and analytics to MyDuck. The audience is a team that already runs MySQL or Postgres and has a reporting problem.

## Two wire protocols, one storage engine

The implementation detail that makes the project work is that MyDuck implements the MySQL wire protocol and understands MySQL syntax, translating queries and executing them in DuckDB, and it separately implements the Postgres wire protocol so DuckDB SQL can be sent with any Postgres client. The reasoning for the second one is stated in the README: DuckDB's SQL dialect closely resembles PostgreSQL, so you can speed up existing Postgres queries with minimal changes. The repo layout shows both servers living side by side, with mysqlutil/, pgserver/ and pgtest/ for the MySQL side and the Postgres side, plus flightsqlserver/ and flightsqltest/ for the FlightSQL path and a transpiler/ directory that sits between the wire and the engine. There is also a compatibility/ directory, and the requirements file pins a single Python dependency, sqlglot with the rs extra at 30.17.0, which is the SQL parsing and transpilation library doing the dialect translation work.

## Zero-ETL replication uses the standard commands

The replication story is the most immediately useful part, and the design choice is that it does not invent a new protocol. MyDuck can function as a MySQL replica or a Postgres standby, replicating from the primary in real time, and it works like standard replication using MySQL's START REPLICA or Postgres' CREATE SUBSCRIPTION commands, which the README says eliminates the need for complex ETL pipelines. If your existing tooling already knows how to set up a replica or a standby, you already know how to attach MyDuck. The consistency story is handled by careful transaction boundary management in the replication stream, so the README claims you will never see dirty data mid transaction, and transaction batching collects updates from multiple transactions and applies them to DuckDB in batches, which reduces write overhead because DuckDB was not designed for high-frequency OLTP writes. The go.mod shows the replication machinery: the Dolt MySQL server and Vitess parser for the MySQL side, pglogrepl and pgx for the Postgres side, and the go-mysql-server and Vitess modules are replaced with ApeCloud forks.

## Columnar IO on top of the standard COPY protocol

The bulk data paths are where a columnar engine can pay off, and MyDuck handles that in two directions. Loading uses the standard MySQL LOAD DATA LOCAL INFILE or the Postgres COPY FROM STDIN commands, and extraction uses COPY TO STDOUT. On top of that, the project adds an end-to-end columnar path: instead of the traditional row-oriented transfer, MyDuck can send query results and receive data uploads in columnar format, implemented as an extension of the standard Postgres COPY protocol, with a syntax such as COPY ... TO STDOUT (FORMAT parquet | arrow). The point is that you keep using a standard Postgres client library while moving Arrow and Parquet payloads rather than rows, which matters when you are pulling a large result set into a dataframe library. The repository carries an myarrow/ directory and an adapter/ directory, and the go.mod pulls in the Apache Arrow Go libraries and the Arrow database connectivity driver, along with gRPC and protobuf for the FlightSQL server.

## Building the server and running the container

The Makefile is a plain Go build with a DuckDB build tag, and the container is built with Docker Buildx for both architectures. The build uses GOFLAGS with the duckdb_arrow tag, which is what links the Arrow support into the binary, and version metadata is injected at link time from git describe and git rev-parse.

```bash
	docker buildx build --platform linux/amd64,linux/arm64 -t $(REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG) --push .
```

```bash
	docker run -d -p 3306:3306 -e MYSQL_CHARSET=utf8  $(IMAGE_NAME):$(IMAGE_TAG)
```

The default image name is myduck with the tag latest under the apecloud registry, and the local build target uses docker/Dockerfile with the load flag so the image stays on the machine. The run target publishes 3306 for the MySQL port and passes the charset through the MYSQL_CHARSET environment variable, and there are matching stop-image and clean-image targets that find the container by image ancestor rather than by a fixed name. The go.mod requires Go 1.26.2, and the module is github.com/apecloud/myduckserver, with the DuckDB Go driver at 2.10505.0 and the driver versions for MySQL and Postgres client libraries present for the tests.

## Where MyDuck Server is the wrong tool

The boundaries follow from the architecture. The first is that a MySQL or Postgres client talking to MyDuck is talking to a translation layer, not to MySQL or Postgres, so any behaviour that depends on server internals, including engine-specific SQL extensions, custom collations, or quirks of a particular version, will differ or fail, and the transpiler has to cover the subset you use. The second is the write path. Replication works by batching updates into DuckDB, which is the right call for analytical loads and the wrong one for a write heavy transaction mix, so MyDuck is a replica and a query engine rather than the system of record. The third is operational maturity. The repository has no GitHub releases, the last push was on 2026-09-19, and the module pins forked builds of go-mysql-server and Vitess, so you are adopting a moving set of dependencies with patches applied by the project rather than upstream. The alternative worth naming is to use DuckDB directly against Parquet files, which skips the compatibility layer entirely and is the better answer when your data is already in object storage, and MyDuck earns its keep when the source of truth is a live MySQL or Postgres that your existing client tools already speak to.

## The wider feature set and the repository shape

Beyond the core, the README lists a set of capabilities that give a sense of the intended scope: standalone mode, where MyDuck runs without replication as a drop-in replacement with a DuckDB heart, supporting CREATE TABLE and transactional INSERT, UPDATE and DELETE; DuckDB in server mode for teams that want to share one instance over the Postgres client library; HTAP architecture support by working with database proxy tools so DML goes to the primary and analytical queries go to MyDuck; and object storage backup and restore. The table of contents also points to sections for querying Parquet files directly, for LLM integration, and for access from Python, which tells you the intended user is a data team rather than a database administrator. The source tree is unusually large for a project of this age, with dedicated directories for binlog handling, a catalog, a delta layer, storage, plugins, extensions, a harness and a devtools folder, and the test surface includes files named for read-only behaviour, query auditing, window function compatibility and generated columns, which reads like a deliberate checklist of the areas most likely to break.

## Conclusion

Adopt MyDuck Server if your analytics queries are written in MySQL or Postgres SQL and are slow on the row store, and if you can accept a DuckDB storage model underneath. Do not adopt it as a replacement for your transactional primary, because the replication path and the OLTP write patterns are different problems. Verify first that the MySQL or Postgres dialect you rely on is in the transpiler's supported set, and that your client library's compatibility with the replication commands is acceptable, since the protocol is implemented in Go rather than by a real MySQL or Postgres server.

## FAQ

### What is MyDuck Server and what does it do?

It is a Go server that stores data in DuckDB and speaks the MySQL and Postgres wire protocols, translating your queries into DuckDB execution. It can run as a replica of a MySQL or Postgres primary, as a standalone server, or as a shared DuckDB instance for a team.

### How does MyDuck Server replicate data without an ETL pipeline?

It acts as a MySQL replica or a Postgres standby using the standard commands, MySQL's START REPLICA or Postgres' CREATE SUBSCRIPTION, and applies the incoming updates to DuckDB in batches while keeping transaction boundaries consistent so you do not see partially applied transactions.

### Can MyDuck Server send query results in a columnar format?

Yes. Besides the standard row-oriented transfer, it extends the Postgres COPY protocol with a columnar format, for example COPY ... TO STDOUT (FORMAT parquet | arrow), so a standard Postgres client library can move Arrow or Parquet payloads.

### How do I build and run MyDuck Server?

The Makefile builds a Go binary with the duckdb_arrow build tag, and the container is built with Docker Buildx for linux/amd64 and linux/arm64 under the apecloud registry with the myduck image name. The run target publishes port 3306 and passes MYSQL_CHARSET through, and the module requires Go 1.26.2.

## Sources

- [apecloud/myduckserver on GitHub](https://github.com/apecloud/myduckserver)
- [Issues](https://github.com/apecloud/myduckserver/issues)
- [License: Apache-2.0](https://github.com/apecloud/myduckserver/blob/main/LICENSE)
- [Project website](https://myduck.io)
- [README](https://github.com/apecloud/myduckserver/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/apecloud-myduckserver
