Skip to content
Go back

Vector vs Fluent Bit: Modern Log Shippers

By SumGuy 11 min read
Vector vs Fluent Bit: Modern Log Shippers
Contents

Two Log Shippers Walk Into a K8s Cluster

Fluent Bit wins for lightweight Kubernetes DaemonSets and single-box home labs, and Vector wins the moment you need heavy log transforms or a centralized aggregator.

You’ve got logs everywhere. Docker, systemd, application stderr, audit trails. They’re all screaming different formats, different log levels, different timestamps. You need to ship them somewhere, Loki, S3, Splunk, ClickHouse, your own Elasticsearch cluster, before your disk fills up and you spend a Friday night crying over cleanup.

Enter the log shipper. Two horses in this race: Vector and Fluent Bit. Both are open source, both are fast, both will send your logs where they need to go. But they solve the problem differently, and picking the wrong one is like hiring a forklift to move a couch. It works, but it’s not the tool for the job.

Which Log Shipper Should Ship Your Logs?

VectorFluent Bit
Binary size~100 MB~15 MB
Memory footprint50 to 80 MB20 to 30 MB
Transform languageVRL, compiled and fastLua, interpreted and slower
Config formatTOMLINI (or YAML)
Kubernetes defaultNoYes, the CNCF standard
Sink plugins80+ officialEssentials built in, plus HTTP

The Contenders

Vector is Datadog’s Rust-based observation engine. Single binary, hundreds of plugins, transforms written in a DSL called VRL (Vector Remap Language). It’s opinionated about doing a lot of work upfront, parsing, filtering, enriching, redacting, before logs leave your box.

Fluent Bit is the Cloud Native Computing Foundation (CNCF) standard. Written in C, smaller footprint, been around longer, absolutely dominates Kubernetes DaemonSets. It’s the Swiss Army knife that weighs less than the knife alone. Transforms done via Lua plugins or built-in filters.

Think of Vector as a full-service logistics operation: receives shipments, scans contents, repackages, labels, routes. Fluent Bit is the postal worker who knows the route and gets it there on time, but won’t rearrange your boxes.

Vector: The Rust Powerhouse

Vector is big, in the best way. It can ingest from dozens of sources: syslog, journald, files, HTTP, Prometheus metrics, Kafka, even Windows Event Log. Parse JSON, syslog, CSV. Transform with VRL. Sink to Loki, S3, ClickHouse, Datadog, Splunk, Kafka, Syslog, HTTP, S3, Azure Blob, basically anywhere.

The killer feature is VRL, Vector Remap Language. It’s a simple, readable scripting language that runs fast. You can parse, transform, filter, enrich, redact all in one place, and it compiles down to native code.

Here’s a real example: you’re getting JSON logs from your app. Some lines are debug noise. You want to redact the user’s email for privacy. You want to add a hostname field.

transforms:
parse_json:
type: remap
inputs:
- app_logs
program: |
. = parse_json!(.message)
.hostname = get_hostname!()
if .level == "debug" {
abort
}
.email = redact(.email, patterns = [r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'], replacement = "[REDACTED]")

That’s one remap transform. Parse JSON, extract fields into the root, add hostname, drop debug logs, redact the email. Done. VRL does this naturally.

Vector’s config is TOML (or JSON). Clean, readable, type-safe. You define sources, transforms, and sinks, then wire them together.

[sources.app_logs]
type = "file"
file_key = "file"
start_at_beginning = true
paths = ["/var/log/myapp/*.log"]
[transforms.parse]
type = "remap"
inputs = ["app_logs"]
program = '. = parse_json!(.message)'
[sinks.loki]
type = "loki"
inputs = ["parse"]
endpoint = "http://loki:3100"

Vector also has observability built in. It tracks its own performance: logs processed, dropped, errored. You can export those metrics to Prometheus or ship them to the same Loki instance. You’ll know instantly if your shipper is drowning.

The downside: Vector is big. The binary is ~100 MB. Memory footprint can hit 50 to 100 MB depending on buffering and transform complexity. In a 1000-pod Kubernetes cluster, that adds up.

Fluent Bit: The Lightweight CNCF Standard

Fluent Bit is the log shipper you’ve probably already run without thinking about it. It’s in almost every Kubernetes cluster, bundled as a DaemonSet logging sidecar.

Why? It’s tiny. ~15 MB binary. 20 to 30 MB memory footprint per pod, even with multiple inputs. It’s stable. It’s fast. The config is dead simple.

[INPUT]
Name tail
Path /var/log/containers/*.log
Parser docker
Tag kube.*
[FILTER]
Name kubernetes
Match kube.*
[OUTPUT]
Name loki
Match *
Url http://loki:3100/loki/api/v1/logs
Labels job=kubernetes

That’s it. Tail the log files, parse Docker JSON, enrich with Kubernetes metadata, ship to Loki.

Fluent Bit uses INI config by default (though YAML support is there, it’s less common). Inputs, filters, outputs. Simple, flat, no nesting.

For transforms, Fluent Bit has built-in filters, modify, nest, grep, record_modifier, and Lua for anything custom. Lua is slower than VRL (because it’s interpreted), but it works.

Here’s that same JSON-parse-and-redact example in Fluent Bit:

-- in a separate Lua file, e.g., /etc/fluent-bit/scripts/redact.lua
function redact(tag, timestamp, record)
local log = record["message"]
local status, parsed = pcall(function() return cjson.decode(log) end)
if status then
parsed.hostname = os.getenv("HOSTNAME")
if parsed.level == "debug" then
return -1 -- drop the log
end
if parsed.email then
parsed.email = string.gsub(parsed.email, "[%w%._%%-]+@[%w%._%%-]+", "[REDACTED]")
end
record = parsed
end
return 2, timestamp, record
end

Then in your config:

[FILTER]
Name lua
Match *
Script /etc/fluent-bit/scripts/redact.lua
Call redact

It works. But it’s wordier, slower, and harder to debug than VRL. Lua is powerful, but you’re writing a full scripting language for a task that VRL handles in 5 lines.

Fluent Bit shines when you don’t need heavy transforms. Tail files, add metadata, ship. It does that better than anything else. And when you do need transforms, Fluent Bit’s ecosystem of built-in filters is solid for common tasks.

Config Syntax: Pick Your Poison

Vector uses TOML:

Fluent Bit uses INI (or YAML):

For a single-box setup, Fluent Bit’s INI is faster to write. For a platform with dozens of shippers, Vector’s TOML scales better because you can template it.

Sinks: Go Anywhere

Both ship to the same places:

Vector has more official sink plugins (80+). Fluent Bit has the essentials built-in and can call out via HTTP. In practice, if you’re shipping to a popular platform, both work.

The difference: Vector’s sinks can do retry logic, batching, and backpressure natively. Fluent Bit’s are simpler, which is fine for most use cases.

Footprint: The Real Numbers

Run both on a modest box (2 CPUs, 1 GB RAM) and tail a busy app log:

On a single server or a home lab? Fluent Bit wins. You’re not paying anything for that extra overhead.

In a 500-pod Kubernetes cluster with a DaemonSet shipper? Vector’s 100 MB binary (pulled once, shared) doesn’t matter. The memory per-pod does. 500 pods × 50 MB = 25 GB overhead for Vector. 500 pods × 25 MB = 12.5 GB for Fluent Bit. That’s real money on your cloud bill.

But if you’re shipping 500 pods to a central logging platform, you might be running Vector as a single central aggregator (not a DaemonSet), collecting from all nodes. Then footprint is irrelevant: you run one beefy Vector instance and route everything through it.

Transform Power: When It Matters

If your logs are mostly structured (JSON from your app), and you’re just adding metadata and filtering, Fluent Bit’s filters are fine. You won’t miss VRL.

But if you’re:

…then Vector’s VRL becomes a force multiplier. You spend less time writing Lua, and your transforms run faster.

Here’s a transform that routes based on log level and application:

transforms:
route_by_level:
type: remap
inputs:
- parse
program: |
if .level == "error" {
.route = "errors_only"
} else if .app == "payment" && (.level == "warn" || .level == "error") {
.route = "payment_alerts"
} else {
.route = "general"
}

In Fluent Bit, you’d write three separate filter rules with Lua callbacks. Doable, but clunkier.

Running Patterns

Fluent Bit as a sidecar: one container per pod, logging just that app.

- name: fluent-bit
image: fluent/fluent-bit:latest
volumeMounts:
- name: app-logs
mountPath: /var/log/app
- name: config
mountPath: /etc/fluent-bit

This is the Kubernetes default. Every pod has its shipper. Simple, isolated, works great.

Vector as a central aggregator: one instance per node or one global instance, all logs routed through it.

apiVersion: v1
kind: DaemonSet
metadata:
name: vector-agent
spec:
template:
spec:
containers:
- name: vector
image: timberio/vector:latest
volumeMounts:
- name: var-log
mountPath: /var/log

This is also common. Run Vector on every node (like Fluent Bit), but use it for heavier transforms before shipping.

Vector as a service: one centralized instance collecting from Kafka, S3 events, HTTP webhooks, and forwarding to your storage backend.

[sources.kafka_input]
type = "kafka"
bootstrap_servers = ["kafka:9092"]
group_id = "vector-group"
topics = ["logs"]
[transforms.parse]
type = "remap"
inputs = ["kafka_input"]
program = '. = parse_json!(.)'
[sinks.loki]
type = "loki"
inputs = ["parse"]
endpoint = "http://loki:3100"

This is where Vector shines. One box doing all the work, reducing load on producers.

Fluent Bit can do centralized aggregation (via Fluent Bit Forward protocol), but it’s less common and less feature-rich.

The Third Option: Promtail & Alloy

Worth mentioning: Grafana’s Promtail was purpose-built for shipping logs to Loki: dead simple, zero config to tail files and add labels. But heads up: Promtail hit end-of-life in March 2026. Grafana folded its job into Alloy, their OpenTelemetry-based agent that ships logs, metrics, traces, and profiles from one binary. Don’t start new deployments on Promtail; reach for Alloy instead.

If you’re all-in on Grafana/Loki, Alloy is the easiest path now. Just tail, enrich metadata, ship. No heavy transforms needed. Think of it as Fluent Bit but tuned for the Grafana stack, and Grafana ships a config converter to migrate old Promtail files over.

When to Pick Each

Pick Fluent Bit if:

Pick Vector if:

Pick Alloy if:

Picking the Shipper That Fits

Both are good. Fluent Bit is the safer default. It’s been battle-tested in millions of Kubernetes clusters. It’s tiny. It works. If you’re not sure what you need, start there.

Vector is the smarter choice if you’ve already got a logging problem that Fluent Bit feels too simple for. If you’re writing Lua transforms that feel hacky, if you’re managing multiple sinks with different rules, if you need to redact PII across terabytes of logs, Vector’s VRL and native transform pipeline will save you pain and CPU.

In a home lab or small infrastructure, Fluent Bit’s smaller footprint and simpler config win the day. In a larger platform, Vector’s power compounds. You’re not just shipping logs; you’re processing them intelligently before they leave your infrastructure.

The real answer? Try both. Spin up a Vector container, throw some logs at it, write a few transforms in VRL. You’ll know in 15 minutes whether it’s overkill for your use case or a missing piece of your observability puzzle.

Your future self will thank you for picking the right tool now, instead of cursing the wrong one at 2 AM when logs are piling up and you’re trying to debug why nothing’s being shipped.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it'll show up above once verified.


Next Post
Bots Ate 90% of My Worker Quota

Discussion

Powered by Garrul . Sign in with GitHub or Google, or post anonymously.

Related Posts