tikv/pd: the placement driver that schedules a TiKV cluster
Placement driver for TiKV. Single node with default ports You can run pd-server directly on your local machine.
At a glance
- What is it?
- PD is the control plane for TiKV. It embeds etcd for fault tolerance, keeps cluster metadata, and decides where every region lives. This review covers what it does, how to run a single node, and where it stops being the right tool.
- Who is it for?
- Adopt PD if you are running TiKV and need a scheduler and metadata store that ships with it, or if you want to read cluster state from the REST API on port 2379. Do not adopt it as a general-purpose service registry or as a standalone etcd replacement; the README is explicit that PD needs TiKV to work.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What PD actually schedules, and who ends up running it
PD is the abbreviation for Placement Driver, and the README states plainly that it manages and schedules TiKV clusters. That single sentence carries most of the design. TiKV stores data in regions, and something has to decide which TiKV node holds which region, move regions when a store fills up, and keep a consistent record of that decision. PD is that something. It is not a database, and it does not serve SQL; the README notes that a cluster can also include TiDB to provide SQL services, which places PD one layer below the query engine.
The audience is therefore narrow and mostly already committed. If you operate TiKV, PD is not optional, because the README says PD needs to run with TiKV to work. If you are evaluating TiKV as a storage layer, PD is part of the package you are evaluating, not a separate purchase. The one group that gets value without running TiKV is tooling authors: the REST API on the client port exposes member and cluster state, and the README's own example reads it with curl. Operators writing health checks or inventory scripts fall into that category.
etcd inside PD, and the two ports that follow from it
The README says PD supports fault-tolerance by embedding etcd. That is the load-bearing architectural fact. Rather than depending on an external etcd deployment, PD runs the consensus machinery itself, so a PD cluster is also an etcd cluster. Every PD node participates in the same raft group, and the metadata that describes the TiKV cluster lives in that embedded store.
The consequence is visible in the port layout. Each PD node listens on two addresses: a client URL on 2379 and a peer URL on 2380. Both numbers come from the README's single-node example and from the Dockerfile, which declares EXPOSE 2379 2380. The client URL serves the REST API and is what TiKV and pd-ctl talk to. The peer URL is the etcd peer channel, used for replication between PD nodes. The README's members response separates the two explicitly, returning peer_urls and client_urls as distinct arrays for each member.
The response also carries a cluster_id in the header and a leader block naming the current leader. That is the etcd model showing through: a PD deployment elects a leader, and the members endpoint is how you find out which node holds it. If you have ever operated etcd, the shape of this API will be familiar, and the operational habits transfer directly.
Building PD from source with make
The README's build section is two steps. First, make sure Go version 1.25 or later is installed. Second, run make, which the README says is equivalent to make build. The result is three binaries in the bin directory: pd-server, pd-ctl, and pd-recover.
The Makefile adds detail the README omits. The default target is build, and the file defines a PD_EDITION variable that must be either Community or Enterprise; the Makefile raises an error before building if it is set to anything else. Community is the default. There is also a DASHBOARD switch: setting DASHBOARD=0 adds the without_dashboard build tag and keeps CGO disabled, while the default path enables CGO because the dashboard is compiled in. If you want a static binary without the dashboard, that flag is the one to reach for.
git clone https://github.com/tikv/pd.git
cd pd
make
ls binAfter make finishes you should see pd-server, pd-ctl and pd-recover listed in bin. The build takes a while on a cold module cache because the dependency set is large; go.sum is copied before the source in the Dockerfile for exactly that reason.
Running a single PD node on default ports
The README's single-node example is the fastest way to see PD come up. It exports HOST_IP, then starts pd-server with a name, a data directory, a client URL and a peer URL. The example uses 2379 and 2380, the defaults.
export HOST_IP="192.168.199.105"
pd-server --name="pd" \
--data-dir="pd" \
--client-urls="http://${HOST_IP}:2379" \
--peer-urls="http://${HOST_IP}:2380" \
--log-file=pd.logTwo things to note. The data directory is a relative path, so the process writes its embedded etcd state into ./pd; pick an absolute path on a real host. And binding to HOST_IP rather than localhost is what makes the node reachable from outside, which the README calls out as the reason to set it. The log goes to pd.log rather than the terminal, so tail that file if startup seems silent.
Once it is up, the README shows how to confirm it. The curl call returns JSON with a cluster_id, a members array, and the leader.
curl http://${HOST_IP}:2379/pd/api/v1/membersYou should see one member named pd, with peer_urls pointing at port 2380 and client_urls at 2379, plus a binary_version field and a git_hash. The README also shows the same request through httpie, which prints the response headers first; those headers include permissive CORS settings, with Access-Control-Allow-Origin set to *. That is worth knowing if you plan to expose the API beyond a trusted network, because the default configuration does not restrict browser origins.
The Docker route and the advertise URL trap
The README offers two ways to get a PD image: build it locally with docker build -t pingcap/pd ., or pull it with docker pull pingcap/pd. The Dockerfile is a two-stage build. A golang:1.25-alpine stage installs make, git, bash, curl, gcc, g++ and binutils-gold, downloads jq 1.6 for pd-ctl, caches modules via go.mod and go.sum, then runs make. The runtime stage is alpine:3.17 and copies in pd-server, pd-ctl, pd-recover and jq. There is a commented workaround for a sqlite3 and alpine 3.19 incompatibility that sets CGO_CFLAGS before make.
The run command is where the README's example diverges from the bare-metal one, and the difference matters.
export HOST_IP="192.168.199.105"
docker run -d -p 2379:2379 -p 2380:2380 --name pd pingcap/pd \
--name="pd" \
--data-dir="pd" \
--client-urls="http://0.0.0.0:2379" \
--advertise-client-urls="http://${HOST_IP}:2379" \
--peer-urls="http://0.0.0.0:2380" \
--advertise-peer-urls="http://${HOST_IP}:2380" \
--log-file=pd.logInside the container PD listens on 0.0.0.0, but it advertises HOST_IP to the rest of the cluster. That split is the point. An embedded etcd cluster exchanges peer addresses, so a node that advertises 0.0.0.0 hands out an address nobody can dial. If you add a second PD container later, the advertise flags are the first thing to recheck, and the README's single-node example does not cover that case at all.
Where PD is the wrong tool, and what to use instead
The clearest limitation is stated by the project itself: as a component of the TiKV project, PD needs to run with TiKV to work. A single pd-server process will start and answer on 2379, but it has nothing to schedule. If you want a general-purpose distributed key-value store with a REST API, PD is not it, and the README points you elsewhere: for a full cluster it directs readers to the TiUP production deployment guide or the TiDB on Kubernetes documentation, both on docs.pingcap.com.
The natural alternative, and the one the comparison actually illuminates, is running etcd on its own. Both use the same consensus core, and PD's members endpoint returns the same peer_urls and client_urls split you would see from etcd. The difference is what sits on top. Standalone etcd gives you a key-value store and leaves placement decisions to you or to whatever you build. PD adds the scheduling layer for TiKV regions and the cluster metadata that TiKV expects, and it is versioned with TiKV rather than independently. If you are not running TiKV, standalone etcd is the smaller, more predictable dependency, and you avoid inheriting PD's release cadence.
A second boundary is operational. Because PD embeds etcd, losing quorum in the PD cluster is not a degraded state you can shrug off; it is a control-plane outage. The README does not document rollback or recovery procedures beyond naming the pd-recover binary, and the repository does not ship a runbook in the files listed at the top level. Treat the three-node minimum as something you learn from the TiKV deployment documentation, not from this README.
Maintenance, licensing, and what an upgrade really costs
The repository is not archived, and the last push was on 2026-08-27, which is recent enough that the project is under current development. The release history supports that: v8.5.8 landed on 2026-08-27, v8.5.7 on 2026-07-09, and v8.5.6 on 2026-04-14. The cadence is patch-driven within the 8.5 line rather than a stream of new minor versions.
Upgrade cost is dominated by the Go toolchain floor. go.mod declares go 1.25.12, and the README asks for Go 1.25 or later, so building from source on an older toolchain fails before it reaches any PD code. The Dockerfile pins golang:1.25-alpine for the same reason. If you consume the pingcap/pd image, that constraint is absorbed by the image and your own build tooling does not matter.
The dependency surface is broad. go.mod lists kvproto, gogo/protobuf, gin, gorilla/mux, grpc-prometheus, aws-sdk-go-v2 packages for config, credentials, kms and sts, plus a metering_sdk. Because PD embeds etcd and speaks the TiKV protocol via kvproto, a PD upgrade is rarely isolated: the kvproto revision in go.mod tracks the TiKV side, and the file carries a commented replace directive specifically for developing PD and kvproto together. Plan upgrades as a cluster operation.
On licensing, LICENSE is Apache-2.0 and ThirdPartyNotices.txt is present at the top level. Apache-2.0 is permissive and includes a patent grant, but the bundled dependencies carry their own terms, and the notices file exists to record them. That is a question for your own legal review, not something this article can settle.
Editorial conclusion
Adopt PD if you are running TiKV and need a scheduler and metadata store that ships with it, or if you want to read cluster state from the REST API on port 2379. Do not adopt it as a general-purpose service registry or as a standalone etcd replacement; the README is explicit that PD needs TiKV to work. Before committing, verify that your Go toolchain is 1.25 or later, that ports 2379 and 2380 are free on the host, and that you have decided whether to build with make or pull the pingcap/pd image.
Frequently asked questions
What are the key differences between TiDB and TiKV?
The README does not compare the two. It only notes that a cluster can include TiDB to provide SQL services, which places TiDB above the storage layer that PD schedules.
What is the tikv/pd cluster and what does the placement driver do?
PD is the abbreviation for Placement Driver, and the README says it manages and schedules TiKV clusters. It also supports fault tolerance by embedding etcd, so a PD deployment doubles as the consensus layer that stores cluster metadata.
How do I download and install tikv/pd?
There is no installer. The README says to install Go 1.25 or later and run make, which produces pd-server, pd-ctl and pd-recover in the bin directory. Alternatively, build the image with docker build -t pingcap/pd . or pull it with docker pull pingcap/pd.
Is there a tikv/pd tutorial for running a single node?
The README's single-node section is the tutorial: export HOST_IP, then run pd-server with a name, a data-dir, a client URL on 2379 and a peer URL on 2380. A curl request to http://${HOST_IP}:2379/pd/api/v1/members confirms the node is up.
Which ports does pd-server use by default?
The README's single-node example uses 2379 for client URLs and 2380 for peer URLs, and the Dockerfile declares EXPOSE 2379 2380. The members API response lists them separately as client_urls and peer_urls.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/tikv-pd)