# Parca Agent, an always-on eBPF profiler that finds its own targets

> parca-dev/parca-agent samples user-space and kernel-space stacktraces 19 times a second through eBPF and turns them into pprof profiles, with automatic target discovery across Kubernetes and systemd and no code changes or restarts. The requirement is a Linux 5.3 or newer kernel with BTF, and the agent writes its profiles to a Parca server for querying over time.

**parca-dev/parca-agent** — eBPF based always-on CPU/GPU profiler auto-discovering targets in Kubernetes and systemd, zero code changes or restarts needed!

- Repository: https://github.com/parca-dev/parca-agent
- Website: https://parca.dev/
- Stars: 749 · Forks: 92
- Language: Go
- License: Apache-2.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/parca-dev-parca-agent

## What the agent does and the kernel requirement

Parca Agent is an always-on sampling profiler that uses eBPF to capture raw profiling data with very low overhead. It observes user-space and kernel-space stacktraces 19 times per second and builds pprof formatted profiles from the extracted data.

The requirement is short and absolute: Linux kernel version 5.3 or newer with BTF. BTF is the kernel's own type information, and without it the agent cannot walk kernel stack frames symbolically, which is most of what an always-on profiler is for. That single requirement is worth checking before anything else, because it rules out older enterprise kernels and some container runtime configurations.

The output is standard pprof. That is a deliberate and important choice, because it means the profiles can be read by the tools people already have: go tool pprof, the standard profiling UI, or anything that accepts the pprof format. A profiler with a proprietary output format would need its own viewer, and the value of an always-on profiler depends on being able to open a flame graph in the tools you already use.

The deployment model is the other thing that distinguishes it. The collected data can be viewed locally via HTTP endpoints, and then be configured to be sent to a Parca server to be queried and analysed over time. So the agent is useful on its own for a quick look, and useful in a fleet for the history.

The design documentation is linked from the README, and the topics on the repository show the scope: C, C++, Go with extended support, Rust, .NET, Deno, Erlang, Java, Julia, Node.js, Wasmtime, PHP 8 and above, Ruby and Python. The README calls that an incomplete list and links the language support documentation and the open issue tracker for further language support work.

One line in that list is worth reading carefully. Go has extended support, which means more than resolving the standard runtime frames: Go's goroutine stacks and inlining behaviour need specific handling, and a profiler that does not handle them produces profiles that are subtly wrong rather than obviously broken.

## Configuration, flags and the precedence rule

The agent is configured through command-line flags or through a YAML configuration file given with --config-path. The configuration file can contain both relabel configurations and any command line flag written with hyphenated names, such as log-level or http-address. Command-line arguments take precedence over the configuration file values.

That precedence rule is the one to internalise, because it is what makes a base configuration file practical in a fleet. You put the shared settings in the file and override the one or two values that differ per node on the command line.

The help output embedded in the README shows the shape of the flag set. There is the logging configuration, with --log-level defaulting to info and --log-format defaulting to logfmt, and structured logging as JSON is the alternative. The HTTP server binds to 127.0.0.1:7071 by default, which is a deliberately conservative default for something that exposes profiling data.

Several flags exist to describe the environment rather than the agent. --environment-type and --machine-id identify the host, and --node sets the name of the node the process runs on, with the note that on Kubernetes this must match the Kubernetes node name, since that is how the server associates profiles with a machine. --tracers controls which tracers are enabled and defaults to all, --include-env-var takes a list of environment variables to include in the profile, and --otel-tags attaches OpenTelemetry tags to all traces so profiles can be correlated with the rest of an observability setup.

--memlock-rlimit is marked deprecated. It used to set the maximum number of bytes that may be locked into RAM, which is needed so the agent can lock memory for its eBPF maps, and zero means no limit. The deprecation tells you the behaviour moved elsewhere, and if you are running on a system with a low memlock limit, that limit is still the classic reason an eBPF profiler fails to start.

For debugging, the README gives the obvious thing: enable debug logging with --log-level=debug.

## Profile types, what needs instrumentation, and the operational caveats

The profile types available are on-CPU, with network usage and allocations listed as coming soon. Runtime specific information, such as goroutines, is explicitly noted as requiring explicit instrumentation.

That distinction is the honest limit of the whole approach, and it is worth being clear about it. An eBPF sampler sees the call stack as the kernel knows it, so it can tell you that your application spent time in a function, but it cannot tell you the state of a runtime's own scheduler. Goroutine dumps, heap statistics and thread stacks are things the runtime knows and the kernel does not, so they still need the runtime's own profiling support.

The other limitation is the container boundary. An agent that samples everything on a node sees every process on it, which in a Kubernetes cluster means the kubelet's containers and anything else sharing the node. The target discovery feature handles finding the right processes, but it also means the agent needs enough privilege to inspect other processes, which in practice means elevated capabilities and often a security context that gives it host access.

That is the real operational cost of this approach and it is not a small one. The agent is a privileged daemon on every node, reading other processes' memory, and the cluster needs to be configured to allow it. Any team deploying it has to accept that trade, and the README's own emphasis on it being zero code changes and no restarts needed is about the application, not the cluster.

On the release side, the versions are frequent, with 0.49.0 in July 2026, 0.49.1 in September and 0.50.0 later that month, and the last push on 2026-10-19. The project is Apache-2.0 licensed, and the repository is packaged as a container and as a snap, with separate build and container workflows in the badges.

## Where it fits against the other profiling options

The alternatives divide into two groups, and the choice is mostly about whether you want to change the application or not.

If you can change the application, the in-process profilers are better in every respect. The Go runtime profiler, the JVM's flight recorder, the V8 CPU profiler, the Python profiler, Rust's own instrumentation: each of them knows the language semantics and produces richer output with no privilege requirements and no eBPF dependency. Their weakness is that they only exist while the process is instrumented, and for a fleet of short-lived containers you may not know which process was slow.

If you cannot change the application, which is the normal case for a platform team, the alternatives are the sampling profilers. perf is the traditional answer on Linux and it works without any privileges for unprivileged profiling, but it samples at the signal level rather than through eBPF, and getting symbolized stacktraces out of it in a container is work. Pyroscope is the closest competitor to Parca in design: continuous profiling, pprof format, written by the Grafana people. The difference is that Parca's agent discovers its targets automatically in Kubernetes and systemd, which is the specific problem it was built for.

There is also the combination approach, which is what a lot of teams end up with: an eBPF agent for the fleet to find the hot path, and the runtime's own profiler attached to the one service that turns out to be responsible. Parca fits naturally into that arrangement, because the pprof format means the output drops into the tooling you already use for the second step.

The honest caveat is the same one as in the previous section. A low-overhead always-on sampler tells you where the time goes, and it tells you that for every process on the node rather than for one service. Deciding what to do with that is still your job, and an always-on profiler that nobody reads is an operational cost with no return.

## Conclusion

Adopt Parca Agent if you need continuous profiling of a fleet without instrumenting your code, especially on Kubernetes where target discovery should be automatic. Skip it if your kernel is older than 5.3 or has no BTF, since the agent cannot run without them, or if you need runtime-specific data such as goroutine dumps, which still require explicit instrumentation. Verify first by running it on one node with the log level at debug, confirming profiles appear at the HTTP endpoints, and checking that the pprof output is readable by your usual profiling tooling before you point a whole cluster at it.

## FAQ

### What does Parca Agent do?

It is an always-on sampling profiler that uses eBPF to capture raw profiling data with very low overhead, observing user-space and kernel-space stacktraces 19 times per second and building pprof formatted profiles from the extracted data. The data can be viewed over local HTTP endpoints or sent to a Parca server for analysis over time.

### What are the system requirements for Parca Agent?

Linux kernel version 5.3 or newer with BTF. The agent depends on the kernel's own type information to walk kernel stack frames symbolically, so a kernel without BTF is a hard blocker regardless of the rest of the setup.

### How is Parca Agent configured?

Through command-line flags or a YAML file given with --config-path, where the file can hold relabel configurations and any flag written with hyphenated names. Command-line arguments take precedence over the file, which lets a shared base configuration be overridden per node.

### Which profile types does Parca Agent support?

On-CPU profiles, with network usage and allocations listed as coming soon. Runtime specific information such as goroutines requires explicit instrumentation, because the eBPF sampler sees the call stack as the kernel knows it rather than the runtime's own scheduler state.

### Which languages does Parca Agent support?

An incomplete list covering C, C++, Go with extended support, Rust, .NET, Deno, Erlang, Java, Julia, Node.js, Wasmtime, PHP 8 and above, Ruby and Python, with the documentation and the open feature issues tracking further language support work.

## Sources

- [License: Apache-2.0](https://github.com/parca-dev/parca-agent/blob/main/LICENSE)
- [parca-dev/parca-agent on GitHub](https://github.com/parca-dev/parca-agent)
- [Project website](https://parca.dev/)
- [README](https://github.com/parca-dev/parca-agent/blob/main/README.md)
- [Releases](https://github.com/parca-dev/parca-agent/releases)

---

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