OLLAMA_MODELS Not Working? Fix It by Platform
Want to go deeper than this article?
Free account unlocks the first chapter of all 25 courses — RAG, agents, MCP, voice AI, MLOps, real GitHub repos.
Ollama’s running. Here’s what to build with it. Go from “ollama run” to RAG apps, agents, and fine-tuned models — structured and hands-on. First chapter free.
Three different mechanisms swallow OLLAMA_MODELS, and which one you have depends on how the server was started. If you use the desktop app, the app overwrites your variable: app/server/server.go copies your environment and then sets env["OLLAMA_MODELS"] = settings.Models from the app's own Model location setting before spawning ollama serve, so the GUI wins - set the GUI path to match. If you run the Linux systemd service, your shell export never reaches the daemon and you need Environment= in a systemd override plus chown -R ollama:ollama on the target. And on every platform, the ollama CLI is a thin HTTP client - setting the variable in the terminal you type ollama list into changes nothing at all.
That last one is worth repeating because it makes the other two invisible. When you export OLLAMA_MODELS=/mnt/big-disk/ollama and then run ollama list, you have configured the client. The client sends an HTTP request to a daemon that was started by launchd, systemd or the desktop app, with a completely different environment. The daemon is the only process whose OLLAMA_MODELS matters.
Below: how to read the path the server is really using, a per-platform truth table, the fix for each failure, and how to move the models you already have without downloading them again.
How do I see which path the server is actually using?
Stop guessing from your shell. The Ollama server prints its entire effective configuration on startup, including the resolved models path, in a log line tagged msg="server config". Every diagnosis on this page starts by reading that line.
| How you run Ollama | Where that line is |
|---|---|
ollama serve in a terminal | Printed to the terminal immediately |
| macOS desktop app | ~/.ollama/logs/server.log |
| Windows desktop app | %LOCALAPPDATA%\Ollama\server.log |
| Linux systemd service | journalctl -u ollama --since "10 minutes ago" |
Inside that line, find OLLAMA_MODELS:. Here is a real excerpt, from the report in issue #17374, where the user had set the variable to C:\models and the app-started server logged something else entirely:
msg="server config" env="map[... OLLAMA_MODELS:C:\Users\sebastian\.ollama ...]"
while running ollama serve by hand in the same session logged OLLAMA_MODELS:C:\models. Same machine, same user variable, two different answers, because the app supplies its own. That comparison is the fastest diagnostic on this page: run ollama serve manually and compare the two config lines.
One gotcha that is not the problem, despite a lot of advice suggesting it: quoting. envconfig.Var() is documented as returning "an environment variable stripped of leading and trailing quotes or spaces", so OLLAMA_MODELS="D:\models" with literal quotes still resolves correctly.
Reading articles is good. Building is better.
Free account = 20+ free chapters across 25 courses, with a per-chapter AI tutor. No card. Cancel anytime if you ever upgrade.
The per-platform truth table
Different platforms fail differently. Find your row.
| Platform / launch method | What sets the daemon's environment | The failure mode you are hitting | The fix |
|---|---|---|---|
| Windows, desktop app | The app's own settings store, which overwrites OLLAMA_MODELS in the child environment | User env var is set correctly and ignored; ollama list comes back empty | Set the app's Model location to the same directory as the variable |
Windows, ollama serve by hand | The environment of that terminal | Works. This is the comparison case that proves the app is the culprit | Nothing, but you must keep the app closed |
| macOS, desktop app | launchd, plus the same app settings store | export in .zshrc is never read by a launchd-started app | launchctl setenv OLLAMA_MODELS "/Volumes/AI/models", restart the app, and check the app's model-location setting too |
| Linux, systemd (official installer) | The systemd unit only | Shell exports are invisible to the service | sudo systemctl edit ollama.service, add Environment= under [Service], reload, restart |
Linux, systemd, path under /home | Same, but the service runs as the ollama user | Error: mkdir /home/you: permission denied, service flaps | Ownership plus traversal, see the Linux section |
| Docker | The container's environment, where HOME is /root | Setting the variable on the host does nothing at all | Change the volume, not the variable: -v /big/disk:/root/.ollama |
| Any, set in your shell only | Nothing. The CLI is an HTTP client | The daemon never sees it | Set it wherever the server starts, per the rows above |
The default path, when the variable is unset, is not a hardcoded per-OS constant. envconfig.Models() returns OLLAMA_MODELS if set, otherwise filepath.Join(os.UserHomeDir(), ".ollama", "models") - it is always the server process's home directory. That is why the official FAQ documents Linux as /usr/share/ollama/.ollama/models: the installer creates the service account with useradd -r -s /bin/false -U -m -d /usr/share/ollama ollama, so /usr/share/ollama is the home directory for the daemon. Same code, different home, different answer.
| OS | Documented default | Where that path comes from |
|---|---|---|
| macOS | ~/.ollama/models | Your home directory, because the app runs as you |
| Linux (official installer) | /usr/share/ollama/.ollama/models | The ollama service account's home, set by install.sh |
| Windows | C:\Users\%username%\.ollama\models | Your home directory |
| Docker (official run command) | /root/.ollama/models | HOME inside the container is /root; the documented command mounts -v ollama:/root/.ollama |
Windows: why the desktop app overrides your variable
This is the single most common cause on Windows, and it is not a mistake in your setup. The desktop app does not merely fail to read your variable - it actively replaces it. From app/server/server.go, in the function that builds the ollama serve child process:
// Copy and mutate the environment to merge in settings the user has specified without dups
env := map[string]string{}
for _, kv := range os.Environ() {
s := strings.SplitN(kv, "=", 2)
env[s[0]] = s[1]
}
...
if settings.Models != "" {
if _, err := os.Stat(settings.Models); err == nil {
env["OLLAMA_MODELS"] = settings.Models
} else {
slog.Warn("models path not accessible, using default", "path", settings.Models, "err", err)
}
}
Your environment is copied in, then the stored setting is written over the top. The app's settings UI calls that field Model location, described in the component source as "Location where models are stored."
The fix, and its two variants
- Match the paths. Open the app's settings and point Model location at the same directory as your
OLLAMA_MODELSvariable. This is exactly the resolution the reporter of issue #17867 confirmed: "Setting Settings -> Model location to the same directory asOLLAMA_MODELSresolved the issue, including after restarting Ollama." - Or bypass the app. Quit Ollama from the tray and run
ollama servein a terminal that has the variable set. The reporter of issue #17374 used exactly this to prove where the override came from.
PR #17401, "app: honor OLLAMA_MODELS over desktop settings path", would invert the precedence, show the effective path in Settings, and disable the Browse button while the variable is in control. It was open and unmerged at the time of writing, so on a current build the GUI still wins. Check its status before assuming your version behaves differently.
The silent-fallback trap
Look at that else branch again. If the stored path fails os.Stat - an unplugged external drive, an unmounted network share, a drive letter that moved - the app drops the setting entirely and starts the server on your home directory instead, logging only models path not accessible, using default at WARN level. The visible symptom is not an error. It is an empty ollama list, or a prompt to re-download models you know you already have. If your models vanished after a reboot, check whether the drive mounted before you check anything else.
The rest of the Windows-specific install surface - per-user installer, custom program directory, the standalone CLI zip - is covered in our Ollama on Windows installation guide.
macOS: does launchctl setenv still work?
Yes, and it is still the documented method, but on a Mac you have to consider the same desktop-app override as Windows, because the app's server-spawning code is shared across platforms.
The FAQ's instruction is unchanged: "If Ollama is run as a macOS application, environment variables should be set using launchctl."
launchctl setenv OLLAMA_MODELS "/Volumes/AI/ollama-models"
Then quit and relaunch the Ollama application. Two things people get wrong here:
.zshrcand.zprofiledo nothing. A launchd-started app never sources your shell startup files. This is the substance of issue #4749, where the reporter set the variable in.zshrcand found it applied only when they launched Ollama from a Terminal.launchctl setenvdoes not survive a reboot on its own. It sets the variable in the current user session's launchd context. If your models directory reverts after restarting the Mac, that is why - re-run it, or install a LaunchAgent that sets it at login.
Because settings.Models is applied in the shared cmd() path rather than in Windows-only code, the app-settings override applies wherever the desktop app spawns the server. Every report on the tracker so far is from Windows users, so treat this as "check it, then rule it out": start the app, read ~/.ollama/logs/server.log, and see which path the server config line contains.
If launchctl genuinely will not stick, the workaround suggested in the #4749 thread is a symlink, which sidesteps the variable entirely:
# with Ollama quit, and the models already moved
ln -s /Volumes/AI/ollama-models ~/.ollama/models
That is a legitimate fallback rather than a hack, because Ollama only ever resolves a path. The caveat is external volumes: if the drive is not mounted at login the symlink dangles, and you are back to an empty model list.
Reading articles is good. Building is better.
Free account = 20+ free chapters across 25 courses, with a per-chapter AI tutor. No card. Cancel anytime if you ever upgrade.
Linux: Environment=, ownership, and mkdir permission denied
Two separate things go wrong on Linux, and they produce different symptoms.
1. The service never sees your variable
The systemd unit is the only environment the daemon has. The documented method:
sudo systemctl edit ollama.service
[Service]
Environment="OLLAMA_MODELS=/mnt/ssd/ollama/models"
sudo systemctl daemon-reload
sudo systemctl restart ollama
Confirm it took with systemctl show ollama -p Environment, then confirm the server agrees by checking the server config line in journalctl -u ollama. Those are two different checks and both are worth doing: the first proves systemd parsed your override, the second proves Ollama used it.
2. Permission denied, and the service flaps
The second failure is louder. From issue #2701, still open:
ollama[37688]: Error: mkdir /home/crystal: permission denied
systemd[1]: ollama.service: Main process exited, code=exited, status=1/FAILURE
and the near-identical issue #2147:
sh[301002]: Error: mkdir /home/lasse/model_drive: permission denied
The reporter of #2147 had already set the target directory to drwxrwxrwx, which is the detail that makes this confusing. Three causes, in the order to check them:
- Ownership of the directory itself. The FAQ is explicit: "On Linux using the standard installer, the
ollamauser needs read and write access to the specified directory. To assign the directory to theollamauser runsudo chown -R ollama:ollama <directory>." - Traversal of every parent. A world-writable folder is unreachable if a parent is not world-executable. On most distributions
/home/youis0750or0700, so theollamaservice account cannot enter it no matter how open the target is. Check withsudo -u ollama ls /path/to/models- if that fails, the mode on a parent is the problem, not the target. - Systemd sandboxing. The unit pasted into #2701 contains
ProtectHome=yesandProtectSystem=full.ProtectHome=yesmakes/homeinaccessible to the service regardless of file permissions, which is why chmod appears to do nothing. The unit written by Ollama's owninstall.shdoes not set those directives, but several distribution packages do - read your actual unit withsystemctl cat ollamabefore blaming permissions.
The cleanest answer to all three is to stop fighting /home: put the models somewhere the service account can own outright, such as /mnt/ssd/ollama/models or /var/lib/ollama/models, then chown -R ollama:ollama it. Broader Linux setup is covered in our Linux local AI setup guide.
How do I move models I already have without re-downloading?
Move two directories, not one. A model is a set of content-addressed blobs plus a manifest that gives them a name. Copy blobs/ without manifests/ and ollama list is empty even though the weights are all there.
# 1. stop the server first - never move files under a running daemon
sudo systemctl stop ollama # or quit the app from the tray / menu bar
# 2. move both directories, preserving structure
sudo mkdir -p /mnt/ssd/ollama/models
sudo rsync -a /usr/share/ollama/.ollama/models/ /mnt/ssd/ollama/models/
# 3. Linux only: hand the whole tree to the service account
sudo chown -R ollama:ollama /mnt/ssd/ollama/models
# 4. point the *server* at it, restart it, then verify
ollama list
Use rsync -a (or robocopy /E /COPYALL on Windows) rather than a drag-and-drop, so nothing is silently skipped. Verify ollama list returns the full set before you delete the original: the old directory is your only backup, and re-downloading is precisely what you are trying to avoid.
Moving to a machine that has no internet at all is a related but different job. The copy Ollama models to an offline PC guide covers checksums, the standalone CLI archive, and the no-installer path. If the reason you are moving models is that a download keeps dying, read why ollama pull gets stuck or crawls first - a partial download you can resume is cheaper than a migration.
Why is ollama list empty after I moved everything?
Work down this list. It is ordered by how often each turns out to be the answer.
| Check | How to test it | What it means |
|---|---|---|
| The daemon is using a different path than you think | Read OLLAMA_MODELS in the server config log line | The variable never reached the server, go back to the truth table |
| The desktop app overrode it | Compare that line against a manual ollama serve | Match the app's Model location to the variable |
You copied blobs/ but not manifests/ | ls both inside the new directory | No manifest means no name, so nothing lists |
| Wrong nesting level | You should see blobs/ and manifests/ directly inside the path | An extra models/ layer is the usual slip |
| Permissions | sudo -u ollama ls <path>/manifests | The service account cannot read what you copied |
| The drive was not mounted at start | Look for the WARN line models path not accessible, using default | The app silently fell back to your home directory |
| You never restarted the server | systemctl restart ollama, or quit and relaunch the app | The path is read at startup, not per request |
If everything checks out and models still do not appear, the Ollama troubleshooting guide has the wider environment-variable reference, and the complete Ollama guide covers the normal install and storage layout.
Honest limitations
- This is a code and tracker reading, not a lab report. The behaviour above comes from
ollama/ollamaonmainand from users' own logs in the linked issues. We do not have every platform combination on a bench and are not going to pretend otherwise. - The desktop-app override is under active change. PR #17401 was open and unmerged when this was written, and issue #17867 was closed. If your build post-dates a merge, the precedence may have flipped in your favour, and the
server configline will tell you in five seconds. - The macOS desktop-app override is inferred from shared code, not from a reproduction:
cmd()inapp/server/server.gois platform-independent, but every report on the tracker so far is from Windows. Verify on your own machine before treating it as established. - Distribution packages differ from the official installer.
ProtectHome, service account names and default paths are all things a distro maintainer can change.systemctl cat ollamabeats any article, including this one. - We have not tested every filesystem. Network shares, exFAT drives and cloud-synced folders introduce their own permission and locking behaviour on top of everything above. A local, natively-formatted disk is the boring choice that works.
FAQ
Why does Ollama ignore OLLAMA_MODELS on Windows?
Almost always because the desktop app supplies its own value. app/server/server.go copies your environment and then overwrites OLLAMA_MODELS with the path stored in the app's Model location setting before it starts the server. Set that field to the same directory as your variable, or quit the app and run ollama serve yourself. Issue #17867 confirms that matching the two paths resolves it.
Do I need to set OLLAMA_MODELS in my shell as well?
No, and doing so is what hides the real problem. The ollama command is a thin HTTP client that asks the running daemon; the daemon's environment is the only one that counts. Set the variable wherever the server is launched: the systemd unit on Linux, launchctl setenv on macOS, the user environment plus the app's settings on Windows.
Where does Ollama store models by default?
macOS ~/.ollama/models, Linux /usr/share/ollama/.ollama/models, Windows C:\Users\%username%\.ollama\models. None of these are hardcoded: envconfig.Models() falls back to .ollama/models inside the home directory of whichever account runs the server, and Linux looks different only because the installer gives the ollama service account a home of /usr/share/ollama.
Why do I get "mkdir ...: permission denied" when the folder is already 777?
Because the mode on the target is not the whole story. The ollama service account also needs execute permission on every parent directory, and /home/you is typically 0700. If your unit sets ProtectHome=yes, systemd blocks /home outright no matter what the permissions say. Run systemctl cat ollama to see the real unit, and prefer a path like /mnt/ssd/ollama/models that the service can own.
Can I just symlink ~/.ollama/models to another drive instead?
Yes, and on macOS it is a reasonable fallback when launchctl setenv will not stick across reboots. Quit Ollama, move the directory, then link the old path to the new one. The caveat is external drives: if the volume is not mounted when the server starts, the symlink dangles and Ollama behaves as though you have no models at all.
Does OLLAMA_MODELS work inside Docker?
Not in the way people expect. Inside the container the home directory is /root, so models land in /root/.ollama/models, and the documented run command mounts a volume there with -v ollama:/root/.ollama. To store models elsewhere, change the bind mount to point at your disk rather than setting a variable on the host, because a host-side variable is never seen by the containerised server.
My models disappeared after a reboot. What happened?
Check whether the drive mounted. If the desktop app's stored model location fails a stat at startup, the code drops the setting and starts the server on the default home directory instead, logging only models path not accessible, using default at WARN level. Nothing is deleted; the server is simply looking in the wrong place, and it will offer to download models you already own.
Sources
- Ollama FAQ - default model paths per OS,
OLLAMA_MODELS, thechown -R ollama:ollamainstruction, and thelaunchctl/systemctl edit/ Windows environment-variable procedures - Ollama Windows documentation - "Changing Model Location", and the note that the uninstaller will not remove models from a relocated directory
- ollama/ollama,
app/server/server.go- the desktop app's environment merge andsettings.Modelsoverride - ollama/ollama,
envconfig/config.go-Models()resolution order andVar()quote stripping - ollama/ollama,
scripts/install.sh- the systemd unit and theuseradd -m -d /usr/share/ollama ollamaservice account - Issues and PRs: #17374 (Windows app ignores the variable, open), #17867 (matching the GUI path fixes it, closed), #17401 (proposed precedence fix, open), #2701 (systemd cannot create the folder, open), #2147 (permission denied in the service file), #4749 (macOS
.zshrcversuslaunchctl)
Ollama’s running. Here’s what to build with it.
Go from “ollama run” to RAG apps, agents, and fine-tuned models — structured and hands-on. First chapter free.
Stop piecing Ollama together from blog posts
Ollama Mastery is 15 chapters end to end — install, model choice, Modelfiles, GPU offload, the API, and the 20 errors that actually happen. Plus 24 more courses.
Liked this? 20 full AI courses are waiting.
From fundamentals to RAG, agents, MCP servers, voice AI, and production deployment with real GitHub repos. First chapter free, every course.
Build Real AI on Your Machine
RAG, agents, NLP, vision, and MLOps - chapters across 25 courses that take you from reading about AI to building AI.
Want structured AI education?
25 courses, 519+ chapters, from $9. Understand AI, don't just use it.
Continue Your Local AI Journey
- PILLARBest Ollama Models 2026: 15 Ranked (Coding, Reasoning, Chat)
- AI on QNAP & TrueNAS: Run Ollama with GPU Passthrough
- AI on Steam Deck: Run Local LLMs with Ollama on SteamOS
- Best Free AI Models to Run Locally With Ollama, No API Key
- Best Local LLMs for Tool & Function Calling (2026 Tested)
- Best Ollama Embedding Models: We Benchmarked All 6 for RAG
- Best Ollama Models for 8GB RAM 2026: 12 Tested Local Picks
- Best Ollama Models for AI Agents 2026: 9 Tested & Ranked
- Best Uncensored Local LLMs: Abliterated Ollama Models
- Build a Local AI Slack & Discord Bot with Ollama + Python
Comments (0)
No comments yet. Be the first to share your thoughts!