Cloud APIs remove inference infrastructure work; local runtimes give a team direct control over selected model artifacts and where inference runs. Ollama now supports both paths, so the product name alone does not identify the execution location. Local disks, logs, model downloads, operators, tools, backups, cloud models, and remote fallbacks all belong in the data-flow and threat model.

Direct answer: Ollama is a developer-oriented model runtime and distribution layer for supported large language models (LLMs). It can execute downloaded models through a local server, route signed-in clients to cloud models, or serve direct authenticated requests at ollama.com. Its CLI, Modelfiles, native /api, and compatibility endpoints simplify integration, but they do not remove the need to decide execution location, identity, authorization, data handling, capacity, and rollback.

Separate Local and Cloud Execution

Ollama exposes similar request shapes across different trust boundaries. Record the selected path explicitly:

Path Endpoint Authentication Where inference runs
Local model through local server http://localhost:11434/api No API authentication On the host running Ollama
Cloud model through signed-in local server Local /api with a :cloud model Ollama server account sign-in Ollama cloud
Direct native cloud API https://ollama.com/api Authorization: Bearer <API key> Ollama cloud
Direct OpenAI-compatible cloud API https://ollama.com/v1 Authorization: Bearer <API key> Ollama cloud
Direct Anthropic-compatible cloud API https://ollama.com/v1/messages Bearer token; x-api-key alone is not accepted Ollama cloud

The local daemon does not validate API keys. A placeholder key required by an SDK is not an access control. Direct cloud APIs require an Ollama API key, which must stay out of browser code, source control, and logs. Compatibility endpoints implement documented subsets, so test the exact fields, streaming events, tool behavior, and errors your client uses. Teams with a strict local-only requirement should disable cloud features and verify egress, rather than assuming a local base URL makes every selected model local.

Ollama is a strong fit when... Evaluate another serving layer when...
A developer or small team needs repeatable local model evaluation High concurrency, continuous batching, or strict throughput SLOs dominate
Offline-capable execution and local artifact control are explicit requirements A managed control plane, global autoscaling, or provider-operated controls are required
A compact CLI, Modelfile, and application API reduce setup work Mature tenant isolation, quotas, audit, and fleet scheduling are mandatory
The team can benchmark the exact model, context, concurrency, and device A hardware-independent capacity promise is expected before testing

How the Local Runtime Works

For a local model, Ollama resolves an artifact, loads it through a supported backend, applies its prompt template and runtime options, then streams or returns the generated response through an API. A cloud model follows a remote data path instead. In both cases, the surrounding application remains responsible for identity, policy, validation, persistence, and any business action.

flowchart LR A["Pull or import a model artifact"] --> B["Select or create a Modelfile"] B --> C["Load model and allocate context"] C --> D["Call native /api or supported /v1 route"] D --> E["Parse and validate model output"] E --> F["Apply business policy or tool action"]

A request passes through five operational stages:

  1. Artifact resolution: Ollama locates a pulled model tag or a supported local model or adapter declared by FROM and ADAPTER.
  2. Model loading: The runtime allocates model weights and context on CPU, GPU, or a split supported by the current platform.
  3. Prompt construction: The model template combines the system message, conversation, and runtime parameters.
  4. Inference: /api/generate handles a prompt-oriented request; /api/chat handles message history and can include tools or a structured-output schema.
  5. Result handling: The final response includes counters and durations that the application can record. Generated text and tool arguments remain untrusted input.

The native API is the clearest contract when you control the integration:

Interface Best use Boundary to test
/api/chat Multi-turn messages, tool definitions, structured output Model support, tool loop, schema validation, streaming
/api/generate Prompt completion, fill-in-the-middle, response metrics Prompt template, keep_alive, stop behavior, streaming
/api/embed Single or batched embeddings for retrieval Use the same embedding model for indexing and queries
ollama ps Inspect loaded models, processor placement, context, and expiry Observe the deployed host; do not infer from model size alone
/v1 compatibility routes Reuse a supported OpenAI client operation Parameters, errors, features, and future behavior are not universally identical

Build Reproducible Models with a Modelfile

A Modelfile records the base artifact, minimum runtime, prompt behavior, adapters, and inference parameters that must travel with an experiment. It improves reproducibility, but it does not enforce authorization or guarantee that generated data is valid.

This code-review example deliberately separates prompt guidance from output enforcement:

dockerfile
# Replace these values with versions and artifacts your team has tested.
REQUIRES 0.14.0
FROM llama3.2:3b

PARAMETER temperature 0
PARAMETER num_ctx 4096
PARAMETER num_predict 512

SYSTEM """
Review the supplied code for bugs, security defects, and performance risks.
Return concise findings. The calling application defines and validates the
required JSON Schema; do not trigger tools or perform external actions.
"""

Save it as CodeReviewer.modelfile, create the local model, and inspect the resolved configuration:

bash
ollama create code-reviewer -f ./CodeReviewer.modelfile
ollama show --modelfile code-reviewer
ollama run code-reviewer

For a controlled environment, record at least the Ollama version, model tag, resolved Modelfile, artifact provenance and license, host and driver details, and test-set revision. A moving model tag or runtime upgrade is a deployment change even if application code is unchanged.

Importing GGUF Models and Adapters

Ollama can serve supported GGUF files and adapters; it is not a general training framework. Train or fine-tune with an appropriate framework, export a supported artifact, and then verify conversion, tokenizer, prompt template, license, and quality before importing it.

dockerfile
FROM ./my-reviewed-model.gguf
# The adapter must match the base model used during training.
ADAPTER ./my-reviewed-adapter.gguf

An adapter built for a different base model can behave incorrectly. Keep the base artifact, adapter, conversion command, and evaluation result together in the model release record.

Use Structured Outputs Without Trusting the Model

Ollama structured outputs can constrain a native chat or generate response to JSON or a supplied JSON Schema. Schema-conforming output is easier to parse, but it can still contain false, unsafe, or unauthorized values; validate both shape and business meaning.

The native endpoint accepts a JSON Schema in format:

bash
curl -s http://localhost:11434/api/chat \
  -H "Content-Type: application/json" \
  -d '{
    "model": "code-reviewer",
    "messages": [{
      "role": "user",
      "content": "Review: function add(a, b) { return a - b; }"
    }],
    "stream": false,
    "format": {
      "type": "object",
      "properties": {
        "issues": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "type": {"enum": ["bug", "security", "performance"]},
              "description": {"type": "string"}
            },
            "required": ["type", "description"]
          }
        }
      },
      "required": ["issues"]
    },
    "options": {"temperature": 0}
  }'

Use one Go contract for the request schema and response validation. This standard-library example reads OLLAMA_API_KEY only when the selected endpoint needs a Bearer token:

go
package main

import (
	"bytes"
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

const reviewSchema = `{
  "type": "object",
  "properties": {
    "issues": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "type": {"enum": ["bug", "security", "performance"]},
          "description": {"type": "string"}
        },
        "required": ["type", "description"]
      }
    }
  },
  "required": ["issues"]
}`

type Message struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

type ChatRequest struct {
	Model    string          `json:"model"`
	Messages []Message       `json:"messages"`
	Stream   bool            `json:"stream"`
	Format   json.RawMessage `json:"format"`
	Options  map[string]any  `json:"options"`
}

type ChatResponse struct {
	Message Message `json:"message"`
}

type Issue struct {
	Type        string `json:"type"`
	Description string `json:"description"`
}

type Review struct {
	Issues []Issue `json:"issues"`
}

func requestReview(
	ctx context.Context,
	client *http.Client,
	endpoint string,
	model string,
) (ChatResponse, error) {
	payload := ChatRequest{
		Model: model,
		Messages: []Message{{
			Role:    "user",
			Content: "Review: function add(a, b) { return a - b; }",
		}},
		Stream:  false,
		Format:  json.RawMessage(reviewSchema),
		Options: map[string]any{"temperature": 0},
	}
	body, err := json.Marshal(payload)
	if err != nil {
		return ChatResponse{}, err
	}
	request, err := http.NewRequestWithContext(
		ctx, http.MethodPost, endpoint, bytes.NewReader(body),
	)
	if err != nil {
		return ChatResponse{}, err
	}
	request.Header.Set("Content-Type", "application/json")
	if key := strings.TrimSpace(os.Getenv("OLLAMA_API_KEY")); key != "" {
		request.Header.Set("Authorization", "Bearer "+key)
	}

	response, err := client.Do(request)
	if err != nil {
		return ChatResponse{}, err
	}
	defer response.Body.Close()
	if response.StatusCode < 200 || response.StatusCode >= 300 {
		message, _ := io.ReadAll(io.LimitReader(response.Body, 4096))
		return ChatResponse{}, fmt.Errorf(
			"ollama returned %s: %s",
			response.Status,
			strings.TrimSpace(string(message)),
		)
	}
	var result ChatResponse
	if err := json.NewDecoder(response.Body).Decode(&result); err != nil {
		return ChatResponse{}, err
	}
	return result, nil
}

func validateReview(content string) (Review, error) {
	var review Review
	if err := json.Unmarshal([]byte(content), &review); err != nil {
		return Review{}, fmt.Errorf("invalid review JSON: %w", err)
	}
	if len(review.Issues) > 20 {
		return Review{}, fmt.Errorf("too many issues: %d", len(review.Issues))
	}
	allowed := map[string]bool{
		"bug": true, "security": true, "performance": true,
	}
	for index, issue := range review.Issues {
		if !allowed[issue.Type] || strings.TrimSpace(issue.Description) == "" {
			return Review{}, fmt.Errorf("invalid issue at index %d", index)
		}
	}
	return review, nil
}

func main() {
	endpoint := flag.String("endpoint", "", "Ollama chat endpoint")
	model := flag.String("model", "code-reviewer", "model name")
	timeout := flag.Duration("timeout", 30*time.Second, "request timeout")
	flag.Parse()

	response := ChatResponse{
		Message: Message{
			Content: `{"issues":[{"type":"bug","description":"add subtracts b"}]}`,
		},
	}
	if *endpoint != "" {
		ctx, cancel := context.WithTimeout(context.Background(), *timeout)
		defer cancel()
		var err error
		response, err = requestReview(
			ctx, &http.Client{Timeout: *timeout}, *endpoint, *model,
		)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	}

	review, err := validateReview(response.Message.Content)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	output, err := json.MarshalIndent(review, "", "  ")
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	fmt.Println(string(output))
}

Run it without flags to exercise the offline validation fixture, or pass -endpoint http://localhost:11434/api/chat to call a local server. For direct cloud access, pass -endpoint https://ollama.com/api/chat, select a hosted model with -model, and inject OLLAMA_API_KEY from a secret manager. Then apply explicit rules such as allowed line ranges, authorization checks, and human approval. OWASP classifies unsanitized model output passed to shells, browsers, SQL, file paths, or privileged functions as improper output handling.

Choose the Native API or OpenAI Compatibility Deliberately

Ollama's /v1 surface supports documented parts of the OpenAI API; it is an interoperability adapter rather than a universal drop-in replacement. Prefer /api for Ollama-specific lifecycle controls and use /v1 when the exact client operation has been tested.

Decision Native /api OpenAI-compatible /v1
Ollama-specific fields and lifecycle Direct access May not map every option
Existing OpenAI SDK integration Requires an Ollama client or HTTP layer Can reduce migration work for supported operations
Local authentication field Controlled by your surrounding service Client key may be required syntactically but ignored by local Ollama
Direct cloud authentication Bearer API key for https://ollama.com/api Bearer API key for https://ollama.com/v1
Compatibility test Pin and test the Ollama contract Also test client version, parameter mapping, errors, and streaming

Do not make a production switch by changing only baseURL. Build contract tests for the operations you use: message roles, streaming chunks, structured output, tools, usage fields, cancellation, timeout, retry, and error mapping.

Measure Context, Model Residency, and Request Cost

Ollama capacity depends on model weights, quantization, context length, concurrency, backend, and device placement. A larger context consumes more memory, and an apparently available model may be partly offloaded to CPU, so measure the deployed combination instead of relying on a generic hardware table.

Use ollama ps to inspect active placement and context:

bash
ollama ps

For API requests, record the final non-streaming response or aggregate the final streaming event. Native responses expose fields including total_duration, load_duration, prompt_eval_count, prompt_eval_duration, eval_count, and eval_duration. Durations are reported in nanoseconds.

bash
curl -s http://localhost:11434/api/generate \
  -d '{
    "model": "code-reviewer",
    "prompt": "Explain one risk of executing model-generated shell commands.",
    "stream": false,
    "keep_alive": "5m"
  }' |
jq '{
  total_ms: (.total_duration / 1000000),
  load_ms: (.load_duration / 1000000),
  prompt_tokens: .prompt_eval_count,
  output_tokens: .eval_count,
  output_tokens_per_second:
    (if .eval_duration > 0
     then (.eval_count / (.eval_duration / 1000000000))
     else null end)
}'

Benchmark complete tasks rather than a single warm request. Separate cold model load from prompt evaluation and token generation, and report P50/P95 latency, failure and timeout rates, memory pressure, processor placement, quality, and concurrent-user behavior. Use keep_alive: 0 when a test must unload the model immediately; use a bounded duration only after measuring the memory trade-off.

Secure an Ollama Service Before Network Exposure

The safest default is loopback access behind an application boundary. Binding Ollama beyond localhost turns a developer runtime into a reachable model service; add controls before changing the bind address.

flowchart LR U["Approved client"] --> G["Gateway: identity, TLS, limits"] G --> A["Application: policy and schema validation"] A --> O["Ollama on a private loopback or network"] O --> M["Approved model artifacts"] A --> L["Redacted metrics and audit events"]
Risk Required control Evidence to retain
Unauthenticated network access Loopback or private boundary, gateway authentication, TLS, firewall Bind address, route policy, access test
Cross-tenant data exposure Application authorization, separate histories and storage, tenant-aware logs Authorization tests and retention policy
Resource exhaustion Request-size, context, concurrency, timeout, and model allowlists Load-test results and rejection metrics
Unsafe model output Schema validation, contextual encoding, parameterized queries, tool approval Negative tests and blocked-action logs
Artifact or license risk Approved source, license review, checksum or provenance record Model inventory and review owner
Unexpected data transfer Egress policy and review of cloud models, telemetry, tools, plugins, and fallbacks Network test and documented data flow

Do not set OLLAMA_ORIGINS="*" as a general production fix. Browser origin policy is not authentication, and a private LAN is not an authorization system.

Ollama vs LM Studio vs vLLM

The right runtime follows the operating model, not a universal speed ranking. Benchmark the same artifact and workload when two runtimes support it.

Runtime Primary strength Important boundary
Ollama CLI-first local model management, Modelfiles, native APIs, and a compatibility layer Surrounding service must provide production identity, policy, tenancy, and fleet controls
LM Studio Desktop-first model discovery, chat, and local experimentation GUI-centered workflows differ from headless service and fleet operations
vLLM Throughput-oriented serving features for supported model and accelerator combinations Requires more explicit infrastructure, model, memory, and operations planning

Choose Ollama when local workflow simplicity and artifact control matter more than maximizing shared-serving throughput. Evaluate vLLM or another serving platform when batching, accelerator utilization, large concurrency, autoscaling, or mature multi-tenant controls are primary requirements.

Production Readiness and Rollback Checklist

A successful local demo proves only that one request ran in one environment. Promotion to a shared service requires reproducible artifacts, workload evidence, security controls, and a rollback path.

  1. Pin and record the Ollama release, model tag, resolved Modelfile, artifact source, and license.
  2. Evaluate representative prompts, adversarial inputs, malformed output, refusals, and domain-specific quality.
  3. Test cold and warm latency, context sizes, concurrency, memory pressure, timeouts, cancellation, and recovery.
  4. Keep Ollama private; enforce identity, tenant authorization, quotas, body limits, and audit in the surrounding service.
  5. Validate model output and tool arguments before rendering, storing, executing, or forwarding them.
  6. Define data retention, log redaction, egress, backup, incident response, and model-removal procedures.
  7. Keep the previous runtime, model artifact, configuration, and evaluation result available for rollback.

Frequently Asked Questions

Does Ollama work without a GPU?

Some model and platform combinations can run on CPU. Whether the result is useful depends on model size and quantization, context, concurrency, backend, target latency, and quality. Test the exact workload and inspect processor placement with ollama ps.

Is Ollama private by default?

Requests to a loopback endpoint can be processed locally, but that does not prove end-to-end privacy. Model downloads, cloud models, application telemetry, tools, plugins, logs, backups, and remote fallbacks can create other data paths. Document and test the complete flow.

Can Ollama replace vLLM?

They overlap but optimize for different operating models. Ollama emphasizes local developer experience and model management; vLLM emphasizes throughput-oriented serving. Compare them with the same model, context, concurrency, hardware, and quality criteria.

Does JSON Schema make model output safe?

No. It constrains response shape and improves parsing. It does not prove factual accuracy, authorization, safe HTML or SQL, allowed file paths, or permission to invoke a tool. Apply normal validation and security controls after parsing.

Conclusion

Ollama makes local model evaluation and cloud model access approachable, but neither path is a complete production architecture. Record where inference runs, keep local daemons private, protect direct cloud keys, use Modelfiles for reproducibility, validate structured output, measure the real workload, and retain a tested rollback path.

Official Sources

Further Reading