How to Write an Ollama Modelfile and Build a Custom Model
Write an Ollama Modelfile that sets a system prompt, temperature and num_ctx, build it with ollama create, run it, and fix the common errors.

An Ollama Modelfile is a plain text file that tells ollama create how to build a custom model: the base model to start from, the runtime parameters to bake in, and the system prompt to send with every request. For the most common case, setting a system prompt, a temperature and a context size, the whole file is four instructions long.
Save it as Modelfile, build it with ollama create reviewer -f ./Modelfile, and start it with ollama run reviewer. The sections below walk through that file line by line, list every instruction and parameter with its documented default, show how to pull and edit the Modelfile of a model you already have, and cover the mistakes behind most "ollama modelfile not working" searches.
Ollama Modelfile example with a system prompt, temperature and num_ctx#
Here's the smallest Modelfile that does something useful:
FROM llama3.2
# lower temperature means more predictable answers (default is 0.8)
PARAMETER temperature 0.3
# context window in tokens (default is 2048)
PARAMETER num_ctx 8192
SYSTEM """You are a senior backend engineer reviewing code.
Lead with bugs, then performance, then style.
Keep answers under 200 words unless asked for more."""
Line by line:
FROM llama3.2names the base model. It's the only required instruction. You can point it at any model from the Ollama library, a local GGUF file, or a directory of Safetensors weights.PARAMETER temperature 0.3lowers randomness. The Modelfile reference lists the default as 0.8 as of October 18, 2026.PARAMETER num_ctx 8192sets the context window, the number of tokens the model can see when it generates the next one. The documented default is 2048, which is small once you paste in code or long documents.SYSTEM """..."""is the system message. Triple quotes let it span several lines. A one-line system prompt can skip the quotes, as in the official example:SYSTEM You are Mario from super mario bros, acting as an assistant.
Lines starting with # are comments. The file isn't case sensitive, and instructions can appear in any order. Uppercase and FROM-first are convention, not requirements.
Build and run the custom model#
ollama create reviewer -f ./Modelfile
ollama run reviewer
ollama create takes the name you want for the new model and the -f path to the Modelfile. ollama run then starts an interactive session with your settings applied. You don't type the system prompt again. It's part of the model now.
To confirm what got built, print the model's Modelfile back out:
ollama show --modelfile reviewer
The custom name works anywhere a model name does. If you call Ollama over HTTP, pass reviewer as the model and the system prompt and parameters come along. The Ollama API examples show the request shapes, and running an Ollama model locally covers getting the base model onto your machine first.
Ollama Modelfile syntax: every instruction#
The format is one instruction per line, INSTRUCTION arguments, with # for comments. As of October 18, 2026 the reference documents these instructions:
| Instruction | Required | What it does |
|---|---|---|
FROM |
yes | Base model: a library model and tag, a GGUF file, or a Safetensors directory |
PARAMETER |
no | A runtime parameter such as temperature or num_ctx |
TEMPLATE |
no | The full prompt template, in Go template syntax |
SYSTEM |
no | The system message inserted into the template |
LICENSE |
no | License text to ship with the model |
MESSAGE |
no | Example conversation turns with roles system, user or assistant |
REQUIRES |
no | Minimum Ollama version, for example REQUIRES 0.14.0 |
CAPABILITY |
no | Declares an extra capability on a GGUF or MLX model |
The FROM line has these documented forms:
# an existing model, optionally with a tag
FROM llama3.2:latest
# a single GGUF file, absolute or relative to the Modelfile
FROM ./ollama-model.gguf
# a split GGUF: keep the original shard names and use a wildcard
FROM ./model-*.gguf
# a directory containing Safetensors weights for a supported architecture
FROM ./my-safetensors-model
Relative GGUF paths resolve against the Modelfile's location, not your shell's working directory. Split shards can also be listed on separate FROM lines instead of using a wildcard. If you're downloading GGUF files, the Hugging Face GGUF docs explain the format and how repositories are laid out.
Ollama Modelfile parameters and their defaults#
Every parameter is written as PARAMETER name value, one per line. These are the valid parameters from the reference as of October 18, 2026:
| Parameter | Type | Default | What it controls |
|---|---|---|---|
num_ctx |
int | 2048 | Context window size in tokens |
temperature |
float | 0.8 | Higher is more creative, lower is more coherent |
top_k |
int | 40 | Keeps only the k most likely tokens; lower is more conservative |
top_p |
float | 0.9 | Nucleus sampling, works together with top_k |
min_p |
float | 0.0 | Minimum probability relative to the most likely token |
repeat_penalty |
float | 1.0 | Penalizes repetition; 1.0 is disabled |
repeat_last_n |
int | 64 | How far back to look for repeats; 0 disables, -1 means num_ctx |
seed |
int | 0 | A fixed seed gives the same output for the same prompt |
num_predict |
int | -1 | Max tokens to generate; -1 is unlimited |
stop |
string | none | Stop sequence; repeat the line for several |
draft_num_predict |
int | 4 (separate draft model) | Speculative draft tokens per step; 0 disables |
A few notes on using them:
- Stop sequences take one
PARAMETER stopline each. Thellama3.2Modelfile printed byollama showhas four of them. Quote the value:PARAMETER stop "User:". seedplus a lowtemperatureis the combination for repeatable output in tests.num_predictcaps the response length. It's handy for a classifier model that should answer with one word.- If you only change one thing, make it
num_ctx. 2048 tokens fills up fast once a system prompt and some pasted code are in play. I'd start at 8192 for coding assistants. Larger windows use more memory, so go up only as far as you need.
Generate a Modelfile from code#
When you maintain several variants (a strict reviewer, a chatty explainer, a one-word classifier), it's easier to generate Modelfiles than to hand-edit them. This script builds one from a dictionary and rejects parameter names or types that aren't in the documented table:
PARAMS = {
"num_ctx": int, "repeat_last_n": int, "repeat_penalty": float,
"temperature": float, "seed": int, "stop": str, "num_predict": int,
"draft_num_predict": int, "top_k": int, "top_p": float, "min_p": float,
}
def modelfile(base, system, params):
lines = [f"FROM {base}"]
for name, value in params.items():
if name not in PARAMS:
raise ValueError(f"unknown parameter: {name}")
values = value if isinstance(value, list) else [value]
for v in values:
want = PARAMS[name]
ok = isinstance(v, want) or (want is float and isinstance(v, int))
if not ok:
raise TypeError(f"{name} expects {want.__name__}, got {v!r}")
shown = f'"{v}"' if name == "stop" else v
lines.append(f"PARAMETER {name} {shown}")
lines.append(f'SYSTEM """{system}"""')
return "\n".join(lines) + "\n"
print(modelfile(
"llama3.2",
"You are a terse code reviewer. Point out bugs first, style second.",
{"temperature": 0.2, "num_ctx": 8192, "stop": ["<|eot_id|>", "User:"]},
))
Redirect the output to a file named Modelfile and run ollama create on it as before.
Where the Modelfile is and how to edit an existing one#
Ollama doesn't keep a Modelfile per model on disk for you to open in an editor. The model is stored as blobs under Ollama's models directory, and the Modelfile is reconstructed on demand:
ollama show --modelfile llama3.2 > Modelfile
The output starts with a comment telling you what to do next. In the official example it reads:
# Modelfile generated by "ollama show"
# To build a new Modelfile based on this one, replace the FROM line with:
# FROM llama3.2:latest
FROM /Users/pdevine/.ollama/models/blobs/sha256-00e1317cbf74d901080d7100f57580ba8dd8de57203072dc6f668324ba545f29
TEMPLATE """..."""
PARAMETER stop "<|start_header_id|>"
PARAMETER stop "<|end_header_id|>"
PARAMETER stop "<|eot_id|>"
PARAMETER stop "<|reserved_special_token"
So the edit workflow is:
- Dump the Modelfile with
ollama show --modelfile. - Replace the
FROM /.../blobs/sha256-...line withFROM llama3.2:latestas the comment suggests. - Add or change
PARAMETERandSYSTEMlines. LeaveTEMPLATEand the existingstoplines alone unless you have a reason. - Run
ollama createwith a new name.
That's also how you modify a custom model you built earlier: show, edit, create again.
TEMPLATE and MESSAGE: when to touch them#
Most Modelfiles don't need a TEMPLATE. The base model already carries one, and the basic example in the reference omits it entirely. You write a template when you're building from raw GGUF or Safetensors weights that don't ship with one, or when the model expects a chat format that differs from what you inherited.
Templates use Go template syntax with three variables:
| Variable | Meaning |
|---|---|
{{ .System }} |
The system message |
{{ .Prompt }} |
The user's message |
{{ .Response }} |
The model's reply; anything after it is omitted |
The reference gives this ChatML-style example:
TEMPLATE """{{ if .System }}<|im_start|>system
{{ .System }}<|im_end|>
{{ end }}{{ if .Prompt }}<|im_start|>user
{{ .Prompt }}<|im_end|>
{{ end }}<|im_start|>assistant
"""
The special tokens are model specific. Copy them from the model's own documentation rather than from a different model's template.
MESSAGE is a lighter-weight tool: it seeds the conversation with example turns so the model answers in the same style. The documented example teaches terse yes/no answers:
MESSAGE user Is Toronto in Canada?
MESSAGE assistant yes
MESSAGE user Is Sacramento in Canada?
MESSAGE assistant no
MESSAGE user Is Ontario in Canada?
MESSAGE assistant yes
MESSAGE system is an alternate way to set the system prompt. LICENSE """...""" attaches license text, REQUIRES 0.14.0 pins a minimum Ollama version, and CAPABILITY decision declares a capability on GGUF or MLX weights trained for it. Repeat CAPABILITY to add more than one.
Ollama Modelfile not working: common mistakes#
- No FROM line. It's the only required instruction. Everything else is optional.
- Wrong path to a GGUF. Relative paths resolve from the Modelfile's location. Use an absolute path when in doubt.
- A multi-line SYSTEM without triple quotes. Wrap anything longer than one line in
""", or only the first line counts. - Several stop sequences on one line. Each needs its own
PARAMETER stopline. - Misspelled parameter names. It's
num_ctx, notcontext_lengthornum_context. The table above is the full list. - Running the base model instead of the new one.
ollama run llama3.2ignores your Modelfile. Run the name you gave toollama create. - Using a blob path from ollama show as FROM. It works on the machine that generated it and nowhere else. Swap it for the model name as the generated comment says.
- Rewriting TEMPLATE for a library model. The inherited template already matches the model. Changing it changes how every prompt is encoded, so keep it unless the model's documentation says otherwise.
A quick lint before you build catches the first few of these. Paste your Modelfile into the text constant:
const text = `
from llama3.2
parameter temperature 0.3
PARAMETER context_length 8192
PARAMETER stop "<|eot_id|>"
PARAMETER stop "User:"
SYSTEM """You review code.
Bugs first, then style."""
`;
const instructions = new Set(["FROM", "PARAMETER", "TEMPLATE", "SYSTEM",
"LICENSE", "MESSAGE", "REQUIRES", "CAPABILITY"]);
const params = new Set(["num_ctx", "repeat_last_n", "repeat_penalty",
"temperature", "seed", "stop", "num_predict", "draft_num_predict",
"top_k", "top_p", "min_p"]);
const problems = [];
let hasFrom = false, stops = 0, inBlock = false;
text.split("\n").forEach((raw, i) => {
const quotes = (raw.match(/"""/g) || []).length;
if (inBlock) { if (quotes % 2) inBlock = false; return; }
const line = raw.trim();
if (!line || line.startsWith("#")) return;
const [word, ...rest] = line.split(/\s+/);
const inst = word.toUpperCase(); // the Modelfile is not case sensitive
if (!instructions.has(inst)) {
problems.push(`line ${i + 1}: unknown instruction "${word}"`);
} else if (inst === "FROM") {
hasFrom = true;
} else if (inst === "PARAMETER") {
if (!params.has(rest[0])) problems.push(`line ${i + 1}: unknown parameter "${rest[0]}"`);
if (rest[0] === "stop") stops++;
}
if (quotes % 2) inBlock = true;
});
if (!hasFrom) problems.push("missing FROM, which is required");
console.log(problems.length ? problems.join("\n") : "no problems found");
console.log(`stop sequences: ${stops}`);
Quick reference#
A Modelfile skeleton with the parameters most people set:
FROM llama3.2 # required; model, ./file.gguf, ./shards-*.gguf, or ./safetensors-dir
PARAMETER temperature 0.3 # default 0.8
PARAMETER num_ctx 8192 # default 2048
PARAMETER seed 42 # repeatable output
PARAMETER num_predict 256 # cap response length; -1 = unlimited
PARAMETER stop "User:" # one line per stop sequence
SYSTEM """multi-line system prompt"""
The commands you'll use:
ollama create reviewer -f ./Modelfile # build
ollama run reviewer # chat
ollama show --modelfile reviewer # inspect what was built
ollama show --modelfile llama3.2 > Modelfile # start from an existing model
Before you build, check five things: FROM is present, parameter names match the table, each stop sequence has its own line, a multi-line SYSTEM sits inside triple quotes, and you're running the new name rather than the base model. When something looks different from this page, the Modelfile reference is the place to confirm the current instructions and defaults.
Quick answers
Where is the Ollama Modelfile located?
Ollama doesn't store an editable Modelfile per model. Models live as blobs under Ollama's models directory, and you print the Modelfile on demand with ollama show --modelfile, then redirect it to a file to edit.
What does num_ctx do in an Ollama Modelfile?
It sets the context window in tokens, which is how much text the model can see when generating the next token. The Modelfile reference lists the default as 2048 as of October 18, 2026, so add PARAMETER num_ctx 8192 or higher for long prompts.
How do I edit an existing model's Modelfile?
Run ollama show --modelfile llama3.2 > Modelfile, replace the blob FROM line with FROM llama3.2:latest as the generated comment suggests, change the PARAMETER and SYSTEM lines, then run ollama create with a new name.
Do I need a TEMPLATE in my Modelfile?
Not for a library model. The base model already carries a template, and the basic official example omits it. Write one only for raw GGUF or Safetensors weights, using Go template syntax with .System, .Prompt and .Response.
What is the Ollama Modelfile format?
One instruction per line in the form INSTRUCTION arguments, with # for comments. FROM is the only required instruction, the file isn't case sensitive, and instructions can appear in any order.
Did this solve it?
One tap. No account.
Sorry about that. What was missing?
from 0 readers
Saved you an hour? Send a tip.
USDC or ETH on Base, Ethereum, Arbitrum and more. Keeps the notes free and the examples running.
Network
0xc783bc5c3fa14cEC3f09A22284bC91C5AF0d59e1
On a computer? Scan the code with your phone wallet, or copy the address.
Pick the network your wallet or exchange uses. USDC works on all six; ETH on Base, Ethereum, Arbitrum and Optimism. Don't send on Tron or Solana: this address doesn't exist there. Tips are optional and unlock nothing; every guide stays free.
Discussion
Start the discussion
Next note