Skip to content

Case Alias Symlinks

Chris edited this page Aug 13, 2026 · 1 revision

Case-Alias Symlinks

When deploying a Bethesda game you may notice that there are multiple Data folders and multiple copies of the same folder in the Data folder

image

This is done to decrease loading times. Which sounds very counter Intuitive. But we need to understand how a game like Skyrim interacts with Proton and why it's such an issue in this game

Why is Skyrim slow to load under proton?

  • Windows filesystems are case-insensitive; Linux filesystems are case-sensitive. Wine bridges that gap in software.
  • When a game asks for a file, Wine first tries an exact-case stat() - fast, one syscall. If the casing doesn't match what's on disk, Wine falls back to listing the entire directory and comparing every entry case-insensitively.
  • The Creation Engine constantly asks for paths in casings that don't match the disk:
  • INI reads use lowercase data<PluginName>.ini, while the folder on disk is Data.
  • Texture/terrain-LOD loads use uppercase Data\TEXTURES..., while the folder on disk is usually never all uppercase.
  • Mesh (NIF) files embed asset paths that are ~99% all-lowercase.
  • The engine also repeatedly asks for Data\Data, a folder that never exists and proving a name is absent costs a full directory scan too
  • On Windows this costs nothing, NTFS keeps a case-insensitive index, so every one of these resolves instantly. The engine has no reason not to be sloppy about casing, and never has been

This is neither an issue with Skyrim or Proton/Wine. Skyrim was designed for an NTFS filesystem where this issue doesn't exist. Wine is doing its job correctly. The issue is modded Skyrim can have hundreds of thousands of loose files and makes wine do its thing far too much


Why this fix helps

  • For each relevant directory, create symlinks named with the other casings, pointing at the real folder:
  • data > Data and DATA > Data in the game root
  • textures > Textures, TEXTURES > Textures, and so on for every subfolder of Data
  • Now every casing the engine asks for exists on disk as a real path, so Wine's exact-case fast path hits on the first try, one stat(), no directory scan.

Benchmarks

The test was from pressing play in Steam to the Continue button in the game being clickable. Deploy mod was set to hardlink. Your hardware can affect loading times, so yours may be even better

Vanilla game (Only SKSE installed)

  • No case alias applied - ~31 seconds
  • Case alias applied - ~31 seconds
  • Launching SKSE Directly (No launch Via steam) - ~20 Seconds

Most of the time here (about 10-15 seconds) is steam taking its sweet time to launch the exe. The reason there is no difference is because vanilla only loads from BSA files which are not affected by this fix.

Tested on my own modlist of ~500 mods.

  • Launch from Mo2 - ~5:15 average
  • No case alias applied - ~2:45 average
  • Case alias applied - ~1:35 average
  • Case alias and CRDW ~1:15 Average

About 4 minutes removed from the worst case scenario (launching in Mo2 on Linux) and best case scenario

Gate to Sovngarde

  • No case alias applied - ~18 Minute average
  • Case alias applied - ~5 Minute average
  • Case alias and CRDW ~4:45 Average

The Cached Recursive Directory Walk mod on its own is fine but the case alias fix is needed to fix the long initial load times. CRDW does not fully take affect until it has created a cache. This plugin only masks the issue caused by Wine after the cache is built but does not remove it like the case alias fix does


The data that shows this issue

The following data was done with my own modlist. We trace the Syscalls made by SkyrimSE.exe

Metric Fix OFF Fix ON Change
Directory entries read 129.0M 4.64M −96.4%
getdents64 (directory reads) 656,785 97,503 −85.2%
newfstatat (file lookups) 3,455,882 349,430 −89.9%
openat 1,082,384 119,842 −88.9%
Failed (ENOENT) lookups 756,311 65,319 −91.4%
Total syscalls captured 5.19M 0.57M −89.1%
Raw trace size 1,506 MB 166 MB −89.0%

Where the scanning went

Directory Fix OFF (scans / entries) Fix ON (scans / entries)
Data 324,227 / 119.9M 7,986 / 2.05M
game root 261,685 / 6.9M 30,314 / 0.45M
Data/SKSE/Plugins 4,958 / 0.98M 4,958 / 0.98M
distinct directories scanned 7,179 4,749

With the fix off, two directories accounted for 98% of all directory reading, and Data alone was re-read 324,227 times in a single launch.


The failed lookups that caused it (fix off)

Requested Times Actually on disk
data (root) 226,149 Data
Data\data 75,112 (never exists — engine bug)
Data\MESHES 52,761 Meshes
Data\SOUND 38,937 Sound
Data\TEXTURES 35,769 Textures
Data\meshes 17,895 Meshes
Data\GRASS 8,069 grass
Data\SCRIPTS 4,672 Scripts

All of these failed lookups drop to 0 with the fix. It also shows why renaming Meshes to meshes wouldn't help, the game still requests files from MESHES. Not an issue on Windows but on Proton this will still cause failed lookups, so we need to make both cases exist to remove them


TLDR

  • Skyrim asks for a file in the TEXTURES folder
  • That folder doesn't exist because it's called Textures
  • Wine does a full directory scan and looks for Textures to give to the game
  • This repeats for every single file, Every time there is a case mismatch wine has to do a full directory scan
  • This full directory scan is fast but not free, The time it takes adds up and really hurts with a large modlist

Other info

  • This feature can be turned off in the quick configure menu
  • Most Bethesda games can use this feature but Skyrim probably benefits the most. Other games don't need this

Clone this wiki locally