Docker Desktop Switched New Containers to the local Log Driver. We Measured What That Changes

Docker Desktop 4.94.0 came out on October 5. One line in its release notes changes where your container logs go: "Changed the default logging driver for new Linux containers to local to enable automatic log rotation and reduce disk usage." Docker Engine, which runs on your servers, did not change. It still writes json-file logs, and by default it never rotates them.
So your laptop and your servers now store logs in two different formats. Most of the time you will not notice, because docker logs reads both. You will notice if something reads the log files directly, such as a collector that tails /var/lib/docker/containers/*/*.log. We wrote the same log lines through both drivers on Docker Engine 29.9.0 and recorded what each one stores, what docker logs gives back, and what a file-tailing collector reads.
TLDR
- Docker Desktop 4.94 uses
localfor new Linux containers. Docker Engine still defaults tojson-filewithmax-sizeunlimited, and Docker's docs say that is only for backward compatibility. - 500,000 log lines (47.9 MB of text) took 83.8 MB with
json-fileand no options.localkept all 500,000 lines in 24.1 MB.json-filecapped at 10 MB x 3 used 23.8 MB, but kept only 142,146 lines. docker logsreturned all 500,000 lines from the uncappedjson-filecontainer and from thelocalone.- Fluent Bit's
tailinput, set up the usual way for a Docker host, read 500,000 records from thejson-filecontainer and 0 from thelocalone. Pointed at thelocalfile directly, it read binary framing that the docker parser could not parse. - A changed default only reaches containers created after the change. Existing containers keep
json-fileuntil you recreate them.
Prerequisites
- Docker Engine or Docker Desktop, and
docker infoaccess sudoon a Linux Docker host, if you want to look at the log files yourself- Optional: the demo repo, which runs every test in this post
What changed, and what did not
Docker has always written container output to files on the host, in a format chosen by the log driver. The default has been json-file since the early days: one JSON object per line, with the text, the stream and a timestamp. Its documentation gives max-size a default of -1, which means unlimited, so one noisy container can fill the disk. The logging overview says Docker keeps json-file without rotation as the default "to remain backwards compatible with older versions of Docker", and recommends local for other cases because "it performs log-rotation by default, and uses a more efficient file format."
The local driver keeps 5 files of 20 MB each per container, so 100 MB of log text, and compresses the files it rotates out. Docker Desktop 4.94 now uses it for new Linux containers. Docker Engine 29.9.0, the newest Engine release when we tested, still reports json-file:
We could not run Docker Desktop on our test machine. The Desktop behaviour in this post comes from its release notes. Every measurement comes from Docker Engine 29.9.0 with the same two drivers. The output above is from a daemon with no logging settings (runs/.../00-default.txt).
The test
The demo repo starts three containers that each print the same 500,000 lines, about 96 bytes each, shaped like access logs:
logs-json-default:json-filewith no options, which is what Docker Engine does out of the boxlogs-json-capped:json-filewithmax-size=10mandmax-file=3, a common hand-made fixlogs-local:localwith its defaults, which is what Docker Desktop 4.94 now does
Then it measures the files each driver wrote, counts what docker logs returns, and runs a real collector against the files. We ran it on a Raspberry Pi 4 (arm64) with Docker Engine 29.9.0 and Fluent Bit 5.1.3. The outputs below come from runs/2026-10-09-engine-29.9.0/ in the repo.
Three things stand out:
json-filecosts more than the text. 47.9 MB of text took 83.8 MB of files, 1.75 times the text, because every line is wrapped in{"log":...,"stream":...,"time":...}. That is about 72 extra bytes per line here. With nomax-size, the file only grows.- Our size cap on
json-filethrew data away. The capped container used 23.8 MB anddocker logsreturned only 142,146 of the 500,000 lines. The rest rotated out. localkept everything in about the same space. It used 24.1 MB and returned all 500,000 lines. The current file was 19.4 MB, uncompressed, framing included. Each of the two rotated files was about 2.3 MB after gzip, and the driver rotates a file at 20 MB before compression.
The two capped setups do not have the same budget. json-file at 10 MB x 3 allows 30 MB. local allows 5 files of 20 MB each before compression, framing included, and it also drops its oldest lines when it reaches that limit. A container that writes more than about 100 MB of log records loses lines with either driver. These lines repeat a lot, so they compressed well; how well your logs compress depends on their content.
The file format is what changes
docker logs returned all 500,000 lines from both uncapped containers, because it reads through the Docker daemon. The files on disk are a different story. Here are the first bytes of each file, from the same run:
json-file writes one JSON object per line, in a file named <id>-json.log in the container's directory. local writes length-prefixed binary records in a local-logs/ subdirectory, named container.log, and the rotated files end in .gz. Docker's docs say these files "are designed to be exclusively accessed by the Docker daemon", and that reading them with external tools "should be avoided".
What a file-tailing collector sees
Many Docker hosts ship logs with an agent that tails the files. We ran Fluent Bit 5.1.3 with its tail input and the docker parser on each container's *.log files, the usual setup for a Docker host:
The json-file container gave all 500,000 records. For the local container the counter reported 0, because *.log in the container directory does not match local-logs/container.log. When we pointed Fluent Bit at that file directly, it read 158,382 records and the parser understood none of them. The tail input splits on newline bytes, which this binary format also uses inside its framing, so the records are fragments: the first one holds only a length byte, and the others hold one message each with binary framing around it, in the form ^Fstdout^P... (shown with cat -v). It also left out the two rotated .gz files.
The capped container's 22,860 is a side effect of the test. Fluent Bit started after the container had finished, so it found only the current -json.log file. A collector that runs all the time can read lines before they rotate, but this run did not test that.
What this means for other collectors depends on how they read:
- Collectors that read through the Docker daemon should keep working, because the daemon reads the
localformat for them, as it does fordocker logs. Grafana Alloy'sloki.source.docker"reads log entries from Docker containers" through the daemon address you give it. Vector'sdocker_logssource connects todocker_host. We did not test either of them withlocal. - Collectors that parse the files as Docker JSON cannot decode
local. Fluent Bit'stailinput with the docker parser is one, as measured above. Filebeat's container input reads files and parses thedockerandcriformats, and thelocalformat is neither. That input is deprecated, and Filebeat's docs say to use thefilestreaminput with itscontainerparser instead.
We tested Fluent Bit only. For the others, the docs above are our source, so test your own agent before you depend on this.
Existing containers keep their driver
The log driver is set when a container is created. Docker's docs say that changing the default "only affects containers that are created after the configuration is changed". We checked it: we created a container, restarted the daemon with local as the default, then created a second one and restarted the first.
We tested this on Engine, not on a Desktop upgrade, but the rule is the same. On a laptop that you upgrade to 4.94, the containers you already have keep the driver they were created with. A container that you remove and run again, or that Compose recreates, gets the new default, unless its configuration names a driver. For a while, one machine can have both formats side by side.
What to do
Check which driver each container actually has, not only the default:
# The daemon default
docker info --format '{{.LoggingDriver}}'
# The driver of every container, running or not
docker ps -aq | xargs docker inspect --format '{{.Name}} {{.HostConfig.LogConfig.Type}}'
On servers running Docker Engine, the risk is the old one: json-file with no limit. Pick a default in /etc/docker/daemon.json. Use local if your collectors read through the Docker API:
{
"log-driver": "local"
}
Or keep json-file for a file-tailing collector and give it a limit:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Restart the daemon, then recreate the containers so that they pick up the setting. As the measurements show, a size cap on json-file means the oldest lines are gone from disk. That is fine if a collector has already shipped them, and a loss if it has not.
On Docker Desktop, you probably need to do nothing. docker logs works with both drivers, and tools that use the same API should too. If you run a file-tailing collector on your laptop, set "log-driver": "json-file" in Docker Desktop's daemon settings, or move the collector to a source that reads through the Docker API. We could not see where 4.94 sets its new default, so run the docker info check above after the upgrade.
In Compose files, set the driver for each service if a service depends on it, so the laptop and the server do the same thing:
services:
api:
image: example/api:1.4
logging:
driver: json-file
options:
max-size: '10m'
max-file: '3'
To clear logs that already fill a disk, see How to Clear Docker Container Logs Properly.
Summary
Docker Desktop 4.94 moved new Linux containers to the local log driver. That is the driver Docker's own docs recommend, and in our test it kept all 500,000 lines in 24 MB of files where unbounded json-file used 84 MB. Docker Engine on servers still defaults to json-file with no rotation, so set a default on purpose. If something reads the files under /var/lib/docker/containers, it needs json-file. If it reads through the Docker API, local is the better default for both laptops and servers. In both cases, check docker inspect, because a new default does nothing for containers that already exist.
Try it hands-on
Run the commands from this article in the browser. Nothing to install.
Docker Terminal Simulator
Practice Docker commands in an interactive browser terminal. Learn images, containers, logs, exec, Dockerfile builds, volumes, networks, and Docker Compose with a live Docker daemon visualization.
Log Aggregation Pipeline Simulator
Follow production logs from applications through collection, parsing, filtering, buffering, sharded indexing, and search. Trigger traffic spikes, parser failures, and slow indexing to see where backpressure builds and logs can be lost.
We earn commissions when you shop through the links below.
Svix
Webhooks as a service
Svix Dispatch sends your webhooks for you: retries with exponential backoff, signed payloads, idempotency keys, and a delivery log your customers can see.
Atomsized
AWS platform engineering and GitOps
Design and automation for reliable AWS and Kubernetes platforms, safer delivery workflows, and preview and UAT environments your engineers can understand and own.
DigitalOcean
Cloud infrastructure for developers
Simple, reliable cloud computing designed for developers
DevDojo
Developer community & tools
Join a community of developers sharing knowledge and tools
SMTPfast
Developer-first email API
Send transactional and marketing email through a clean REST API. Detailed logs, webhooks, and embeddable signup forms in one dashboard.
QuizAPI
Developer-first quiz platform
Build, generate, and embed quizzes with a powerful REST API. AI-powered question generation and live multiplayer.
Want to support DevOps Daily and reach thousands of developers?
Become a SponsorTags
Found an issue?
Related Posts
Also worth your time on this topic
5 Advanced Docker Features Worth Knowing
Go beyond Docker basics with BuildKit, multi-stage builds, health checks, init processes, and build secrets. Learn practical techniques that improve security, performance, and reliability.
Log Aggregation Strategies
How do you implement centralized logging in a distributed system? What are the key components?
mid
Monitoring & Observability Checklist
Comprehensive checklist for implementing monitoring, logging, tracing, and alerting across your infrastructure and applications.
60-90 minutes