Releases
TinyWebUI: A Self-Hosted ChatGPT Alternative with Web Search and Memory Built In
TinyWebUI is a self-hosted AI chat interface you start with one command. It works with any OpenAI-compatible endpoint, including Ollama, LM Studio, vLLM, llama.cpp, OpenRouter, Groq and OpenAI. Web search (TinySearch) and long-term memory (TinyContext) come already connected over MCP. Your chats, documents and tool output stay in one SQLite file on your machine.
npx tinywebuiOpen http://127.0.0.1:7777, point it at a model, and ask something that needs the web. That is the whole setup.
Why another local chat UI?
Most self-hosted chat UIs hand you a blank model. Before it can do anything useful you have to find a search provider, sign up for an API key, wire up a tool server, and work out how memory should work. Each step is a chance for the setup to stall.
TinyWebUI starts from the other end. A fresh install can already:
- Search the web and read pages, with sources attached, without a search API key.
- Remember things across chats, and recall only what fits the context window.
- Read your documents: PDFs, DOCX, source files, CSV and JSON.
- Search your past conversations by meaning, not just exact words.
And it stays small. There’s no hosted backend, no account, no build step and no frontend framework. It’s a Node.js server and a SQLite file.
What you need
- Node.js 22.13 or later.
- uv, which launches the bundled TinySearch and TinyContext servers. It fetches them, and Python 3.12 if needed, on first start. Without uv, TinyWebUI still runs; the two servers show needs uv until you install it and restart.
- A model endpoint. A local runtime or a hosted API key.
Connect a local model (Ollama, LM Studio, vLLM, llama.cpp)
Create tinywebui.config.json in the folder you run from, point baseUrl at your runtime’s OpenAI-compatible API, and leave out the API key:
{ "baseUrl": "http://localhost:11434/v1", "model": "qwen3:14b"}Common base URLs:
| Runtime | baseUrl |
|---|---|
| Ollama | http://localhost:11434/v1 |
| LM Studio | http://localhost:1234/v1 |
| llama.cpp server | http://localhost:8080/v1 |
| vLLM | http://localhost:8000/v1 |
Pick a model that handles tool calls reliably. Web search and memory are MCP tools, and a model that can’t call tools will ignore them.
Or use a hosted model
OpenRouter gives you hundreds of models behind one key:
{ "baseUrl": "https://openrouter.ai/api/v1", "apiKey": "sk-or-...", "model": "deepseek/deepseek-v4.1-flash"}You can also pass the key as OPENROUTER_API_KEY or TINYWEBUI_API_KEY. The key is never sent to the browser. The Settings panel writes every change back to the config file, so keep the file out of git.
Web search: TinySearch is already connected
TinySearch searches the web, reads the best pages, reranks the passages locally and hands the model only the evidence worth putting in its context, each piece with its source URL. When a page needs clicking or scrolling, it can drive a browser.
Raw web pages make bad context. They’re full of navigation, cookie banners and boilerplate, and they eat the context window. TinySearch exists to keep that out of the model’s context. Raw webpages are bad context explains why it matters.
Long-term memory: TinyContext is already connected
TinyContext gives the model memory across chats. It saves short facts, like your preferences, decisions, and what you worked on last week, into local SQLite. When they’re relevant, it recalls them with hybrid keyword and vector search, trimmed to a token budget.
So the model doesn’t start every chat from zero, and you don’t pay to resend your whole history. Stable facts about you are attached to every recall automatically. Everything else is ranked against what you’re asking.
Add your own MCP servers
The two TinySuite servers are a default, not a lock-in. Add any MCP server in mcp.json, in the same format MCP desktop clients use:
{ "mcpServers": { "files": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "."] }, "research": { "url": "http://127.0.0.1:8000/mcp" } }}Stdio, Streamable HTTP and SSE all work. You can also manage servers from the MCP panel, which reconnects without a restart. Note that once mcp.json exists, it’s in charge: keep the tinysearch and tinycontext entries in it if you still want them.
Tool approval. Any call that can change something waits for allow, always allow or deny, with its arguments shown. Tools marked read-only run without asking, and read-only calls in the same round run in parallel.
Features that matter after the first day
- Durable turns. A running turn belongs to the server, not the browser tab. Reload, close the laptop, come back, and it’s still going. Press Enter mid-turn to steer it.
- Documents without pasting walls of text. Attach a PDF and the model reads the relevant passages with
read_documentinstead of loading the whole file into context. - Images. JPEG, PNG, WebP and GIF are sent as-is. HEIC and AVIF photos from your phone are converted automatically.
- Local hybrid search. BM25 plus a small on-device embedding model, combined with Reciprocal Rank Fusion. It searches documents and past chats, and nothing leaves the machine. Run
npx tinywebui models pull fastonce to enable the semantic half (about 90 MB). - Long chats stay cheap. Prompt prefixes are deterministic, so provider caches get reused. Large tool results are compacted once, and the full output stays one
expand_contextcall away. - An honest token count. Every round shows input, output, cache reads and cache writes. The statistics view breaks each request down by where its tokens went.
- Automations. Cron-scheduled prompts that run in a chat of your choice. The model can create them too.
From personal tool to team deployment
TinyWebUI starts with no login, bound to 127.0.0.1. When you need more, change authMode:
| Tier | authMode |
For |
|---|---|---|
| Just you | "none" |
Your own machine |
| Just you, remotely | "single" |
A password, set with npx tinywebui set-password |
| Users and admins | "trusted-header" |
A team behind an SSO gateway, with roles and an admin panel |
Every setting can also come from version-controlled config that hot-reloads and refuses typos. There’s a Docker image for servers, with /healthz and /readyz endpoints.
Is TinyWebUI a good Open WebUI alternative?
It depends on what you want. Open WebUI is a large, feature-rich platform. TinyWebUI is deliberately small: one npx command, no Docker needed, no framework, and a codebase you can read in an afternoon. Its focus is a chat that does real research out of the box while keeping the context window, and your bill, under control.
If you already run Open WebUI and only want web search, you can add TinySearch to Open WebUI over MCP. If you want the whole thing working in one step, start with TinyWebUI.
FAQ
Is TinyWebUI free? Yes. It’s open source under AGPL-3.0. Web search through TinySearch needs no paid API key. You pay only for your model, and a local model costs nothing.
Does it work offline? The chat UI, document search and memory all run locally, so with a local model they work without the internet. Web search obviously needs a connection: queries go to search providers, and reading a page contacts that website.
Where is my data stored?
In tinywebui.db, a SQLite file next to your config. Deleting a chat also deletes its documents, tool output and search vectors. There’s no cloud sync.
Which models work best? Any model with reliable native tool calling. Small local models can chat, but research turns work much better with a model that’s good at using tools.
Can I remove TinySearch or TinyContext?
Yes. Edit mcp.json to drop them, or set "disabled": true to keep them defined but disconnected.
How do I check that everything is set up?
Run npx tinywebui doctor. It checks Node, your config, the database, the model endpoint and each MCP server.
Get started
npx tinywebuiRead the TinyWebUI docs, see the product page, or browse the source on GitHub.