Data Plane

A data plane is the set of components that carry the actual workload, while the control plane beside it decides what should exist and schedules work onto them.

A data plane is the set of components that carry the actual workload: the machines, processes, and network paths that work passes through on its way to a result. The control plane sits beside it and decides what should exist and where work should go, without carrying the work itself.

The split describes responsibility rather than hardware. Two processes on one machine can belong to different planes, and a single plane can span several accounts, regions, and providers.

Definition

A component belongs to the data plane when it sits on the path of the work. Remove it and work already in flight stops. Remove a control plane component and existing work continues on whatever was already placed, until something needs to change.

Three properties follow from that position.

It scales with volume. Data plane capacity is sized against how much work arrives: requests per second, packets per second, or, in a build system, concurrent jobs. Control plane capacity is sized against the rate of change, which is usually smaller by orders of magnitude. A fleet running 500 concurrent jobs needs 500 machines and one scheduler.

Its failures are immediate. A data plane outage stops work that is running. A control plane outage stops new decisions while placed work continues, a property AWS describes as static stability. Systems are usually designed so the data plane keeps serving through a control plane outage.

It holds the workload's own material. Source code, secrets, intermediate files, and build outputs all pass through the data plane, so a question about where those things live is a question about where the data plane runs. The control plane holds descriptions instead: identifiers, labels, sizes, timestamps, and the record of what should exist.

DimensionControl planeData plane
JobDecides what should exist and issues instructionsExecutes the work and moves the bytes
Sized againstRate of change, such as decisions per minuteVolume of work, such as concurrent jobs
Effect of an outageNew changes stall, placed work continuesWork in flight stops
HoldsIdentifiers, labels, configuration, desired stateThe workload's inputs, secrets, and outputs
Usual placementCentral, operated once for many workloadsWherever the work has to run

The vocabulary comes from network routing. Inside a router, the control plane runs the routing protocols that build the forwarding table, and the data plane, also called the forwarding plane, moves packets according to that table at line rate. Kubernetes reuses the same division: the API server and the scheduler decide which node should run a pod, and the kubelet with the container runtime on that node runs it.

Where the boundary is drawn

The boundary is a design choice, and the same system can be cut at different points. A managed database can place query execution and storage in one account while the provisioning and upgrade logic runs elsewhere. A build platform can place the queue watcher and the machine lifecycle logic outside a customer account while every compiler process runs inside it.

Two questions settle where the line falls for any given system. Which components would a running workload notice the loss of within seconds, and which components does the workload's data physically pass through. Everything answering yes to either question is data plane.

Why placement is a data plane question

Because the data plane carries the work, the decisions that follow from placement attach to it: which region the machines sit in, which account owns them, which network they join, and which quotas they consume. A team can therefore adopt scheduling operated by someone else while keeping execution on machines it controls, and the reverse arrangement is equally possible.

Example

GitHub Actions splits along this line by default. GitHub holds the queue, evaluates workflow triggers, and matches the labels in runs-on against online runners, which is control plane work. The runner machine performs the steps, which is data plane work.

name: build

on:
  push:
    branches: [main]

jobs:
  package:
    runs-on: [self-hosted, linux, x64]
    steps:
      - uses: actions/checkout@v4
      - run: make build
      - run: make package
      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/

The runs-on line is where the boundary appears in the file. Everything above it describes a decision made outside the machine. Everything below it happens on the machine that claims the job.

Now place that runner on an instance inside a cloud account you own, with the scheduling loop running outside the account. One job then reads like this:

StepWhere it happensPlane
A push creates a workflow run and queues the package jobGitHubControl plane
A scheduler sees the queued job and calls the cloud API for a machineOutside the accountControl plane
The instance boots in the account's VPC and registers with GitHubInside the accountData plane
actions/checkout clones the repository onto the instance diskInside the accountData plane
make build compiles and writes to the instance disk and the cache bucketInside the accountData plane
Step logs and the job conclusion stream back to GitHubAcross the boundaryBoth
The instance is terminated after the job finishesInside the accountData plane

The source tree, the compiler, the secrets exposed to the step environment, and the produced artifact stay on the instance. What crosses the boundary is the instruction to create a machine, the log stream, and the conclusion of the job. The runner agent opens an outbound connection and waits for work, so the machine needs no inbound path for any of this to function.

One documented arrangement of that shape places a VPC with public and private subnets, a security group attached to every runner instance, an object storage bucket for caches and logs, and per-job instances inside the account, while the scheduling loop stays outside it. The resource graph is drawn in the BYOC AWS architecture reference, and the three setup steps for a cloud account are listed in the bring-your-own-cloud documentation.

Sizing follows the plane it belongs to. Because data plane capacity tracks concurrent work, the account quotas that matter are the ones counted per job: instance count, attached volumes, and one elastic IP for each concurrently running job, plus three for the NAT gateways in three availability zones. The AWS guide in that same documentation lists them per stack. The scheduler outside the account needs none of those numbers to grow, because its work grows with the number of decisions rather than the number of machines.

FAQ

What is a data plane?

A data plane is the set of components that carry the actual workload: the machines, processes, and network paths the work passes through on its way to a result. A component belongs to the data plane when removing it stops work that is already in flight.

What is the difference between a control plane and a data plane?

The control plane decides what should exist and issues instructions. The data plane executes. Control plane capacity is sized against the rate of change, data plane capacity against the volume of work, and an outage on each side looks different: losing the control plane stalls new decisions while running work continues, and losing the data plane stops the work itself.

Where is the data plane in a GitHub Actions workflow?

The runner is the data plane. GitHub queues the job and matches the labels in runs-on, and the runner machine performs the checkout, compiles the code, holds the secrets in the step environment, and writes the artifacts. The runs-on line is where the boundary between the two planes appears in the workflow file.

Start with $10 in free credits

Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.