appwrite/docker-ollama: Baking AI Models Into Docker Layers
How Appwrite uses a build-time Ollama server, multi-arch Docker tricks, and pre-pulled weights to make local inference start instantly.
- Appwrite’s repo treats LLM weights like build artifacts, not runtime downloads.
- The build-time Ollama server turns first-start latency into cached Docker layers.
- The runtime script protects the trick by checking that the requested model already exists locally.
- The project is less a standalone toy and more plumbing for AI inside Appwrite’s backend stack.
The interesting thing here is not that Appwrite ships an Ollama image. It is that the repo moves model fetching into docker build, which changes the economics of startup. The container does the slow work once, then starts like a normal service later.
The trick: model pulls happen before the container ever runs
The Dockerfile starts a temporary ollama serve process inside a build step, waits until the API wakes up, and then pulls the target model. That means the model files land in image layers, not in a frantic first-boot download.
RUN ollama serve & \
until ollama list >/dev/null 2>&1; do sleep 1; done \
&& ollama pull ${MODELS}
That is the core move. A model pull is usually a startup tax. Here it becomes a build-time cost that Docker can cache, reproduce, and distribute.
Why Appwrite cares about instant AI startup
The default model choice points to the real use case. The repo ships with embeddinggemma, which says this is not primarily about chat toys. It is about embeddings, retrieval, and backend features that need local inference to feel native.
We are working on ollama integration right now :D
| Goal | Typical Ollama setup | appwrite/docker-ollama |
|---|---|---|
| Primary focus | Run models locally | Package local inference for Appwrite |
| Model acquisition | Pull after startup | Pull during image build |
| Startup behavior | Wait for downloads if needed | Start with weights already present |
| Operational feel | General-purpose runner | Backend plumbing for a platform |
| Best fit | Exploration and manual use | Repeatable Appwrite deployments |
That makes the project feel less like a wrapper and more like infrastructure. Appwrite is trying to make local inference behave like any other backend dependency: declared once, present when needed, invisible when it works.
How the image build works without collapsing
The build-time daemon pattern is clever, but it also needs guardrails. The repo uses architecture-aware logic, readiness polling, and strict shell settings so the optimization does not turn into a fragile shell trick.
#!/usr/bin/env bash
set -euo pipefail
if [[ -n "${MODELS:-}" ]] && ! model_exists "${MODELS}"; then
echo "Model not found locally"
fi
exec ollama serve
The runtime script is simple on purpose. It checks for the model, then hands control to ollama serve. That keeps the build-time shortcut from becoming a hidden assumption at runtime.
This is a platform strategy, not a standalone tool
The repo reads like plumbing for Appwrite’s broader AI story. If you are building with Appwrite, the value is not a new model runner. The value is that local inference can slot into the platform the same way storage or auth does.
| Project | Primary goal | What it optimizes for |
|---|---|---|
| appwrite/docker-ollama | Baked-in local inference | Platform integration and instant startup |
| Official Ollama Docker | General local model runner | Flexibility and simplicity |
| Docker Model Runner | OCI-native model distribution | Docker Desktop integration |
| LocalAI | Broad OpenAI-style backend | Feature breadth and backend variety |
That positioning matters. Appwrite is not trying to win the entire model-serving market. It is making sure its own developers can treat AI like a first-class backend capability.
What it beats, and what it gives up
Compared with the official Ollama image, Appwrite’s version is less generic but more opinionated. Compared with Docker Model Runner, it is less about OCI-native model distribution and more about practical bundling. Compared with LocalAI, it is narrower but simpler to operate.
The trade-off is obvious: bigger images, slower registry pushes, and less flexibility at build time. The payoff is equally obvious: predictable deployments, offline readiness, and no first-run model download.
Why the repo feels unusually mature for plumbing
The polish shows up in the details. Multi-arch builds, smoke tests that hit /api/embed, named volumes for persistence, and strict shell mode all point to a repo that is meant to be depended on, not admired from a distance.
That is the real signal. This is not a hack that happened to work once. It is a repeatable way to ship model weights the same way teams already ship containers.