mabel.ink

The advice I borrowed, and then measured

September 10, 2026

The first version of my Valheim server README had a rule in it, stated flatly: do not keep the game install on Azure Files. The server downloads about 2.1 GB of game files, and the README said that download had to happen fresh on every start.

I had not tested that. I had read it in an upstream discussion on the Docker image's repository (valheim-docker discussion 389), and I built the whole design around it. The overview of the project is here. This post is about the one rule in it that turned out to be wrong.

Why it sounded right

The advice was plausible, which is the dangerous kind. Azure Files is an SMB network share, and SMB is slow when you ask it for lots of small files, because every file costs a network round trip. A game install is thousands of small files. Steamcmd, the tool that installs and updates the server, mounts a share like that and starts hardlinking and checksumming. It sounds like a recipe for pain.

It never got questioned. I wrote it down, and then a document I had written myself started to look like evidence.

How I measured it

One number, taken the same way each time: seconds from the container starting to the log line Game server connected. That is the moment a player could actually join. I ran each configuration and read the boot log.

Configuration Start to joinable
Ephemeral, full 2.1 GB download, plus 8 mods 139 s
Persisted, with validation 179 s
Persisted, update check but no validation 86 s
Persisted, no steamcmd call at all 57 s

The persisted install was slower than the borrowed advice's own alternative in one case, and much faster in the other two. Same share, same files, three very different answers. So "persist on Azure Files" was never really the variable.

Why validation was the whole story

Validation tells steamcmd to checksum every installed file against what Steam says it should be. Over a local disk that is quick. Over SMB it is a round trip per file across thousands of files, so it is bound by latency rather than bandwidth. That is why it took 179 s, which is longer than downloading all 2.1 GB fresh to the container's local disk.

Turn validation off and the picture flips. In the boot log, steamcmd's update check completed in about 18 s.

The first time I tested this I made a different mistake. I measured only the validated case, saw 179 s, and nearly closed the question with "persisting is slower." I only tested the other settings because someone pushed back on those numbers.

One more number that supports the same story. The first install onto the share took 9 minutes 4 seconds, against 98 seconds on local disk. A single slow event hides inside every fast steady state.

What I chose

The server runs with updateOnStartup on and validateOnInstall off. It still patches itself, and the 29 seconds between the 86 s and 57 s cases is what that costs me per start. I decided that was a fair price for not having to remember a manual update cycle every time the developers ship a patch.

There is a side effect I did not plan for. With the install persisted, setting updateOnStartup to 0 genuinely pins the game version, which had been impossible while the install was ephemeral. It is a deliberate freeze for the day a patch breaks the mods.

What I did not measure

Start time is not play time. I have not rigorously measured how the game behaves at runtime with its assets sitting on SMB, things like world load time or hitching during play. Only the start was timed. If runtime ever disappoints, a single setting reverts to the old ephemeral model, and that is written down as the exit.

I would rather say that plainly than let a clean table imply more than it shows.

The lesson

The README rule was not wrong because anyone lied. It was wrong because I treated a report from someone else's setup as a fact about mine, and then my own documentation carried it forward with more authority than it had earned.

What I do now:

The advice was not stupid. It just belonged to someone else's numbers.