How much memory will your search need?
Plan on twice to three times as much memory as the text you actually search, filter or sort on; that is the range the Typesense system requirements page gives for keyword search. To work it out for your data, follow these steps.
- List the fields people search, filter or sort by. Only their values count, not their names, and anything you only display can stay out of the schema and live on disk.
- Multiply the bytes per record by the number of records. The docs' own example, 1 million albums at 204 bytes each, comes to 204 MB of data and 408 to 612 MB of index.
- Using semantic search? Each vector costs 7 bytes for every dimension. A built-in embedding model needs another 2 to 6 GB, while calling an outside embedding service costs no extra memory.
- Leave headroom. The production guide wants memory use under 85% of the machine, plus a small swap file you never actually touch.
Typesense needs at least 2 vCPUs and uses every core it finds. The disk must hold at least your raw data, and the docs recommend SSDs.
The server that fits your index
Once you have a memory figure, the choice is short. Our own rule of thumb is to divide your index estimate by 0.85, then pick the next memory size a server offers (8 GB is the smallest).
| Your index estimate | Kind of server | Why |
|---|---|---|
| Up to a few GB | A small cartridge, ideally with NVMe | One job per machine, the whole box yours |
| Tens of GB | An everyday single-processor server or a two-processor one | Room for the index plus your app beside it |
| Hundreds of GB | A two-processor server with a large memory option | The index stays in one machine's memory |
| Beyond that | A four-processor maximum-memory server | For the job you cannot split |
Every option on the dedicated server page is a whole physical machine with root access and an unmetered port, so busy search traffic never turns into a bandwidth bill. Cartridges with NVMe disks are on the NVMe server page. If a firewall mistake could lock you out, pick a rack server, a blade or the m510 or m710x cartridge, which give you the screen and the power button remotely; the remaining cartridges can only be powered on and off. Avoid the X-Gene cartridge (ARM), which runs only Ubuntu 16.04 and 18.04, since Typesense 26.0 and newer need Ubuntu 20 or later.
A ready server is handed over within 30 minutes of approval, and a custom build takes hours rather than minutes. You manage the server; we keep the hardware and the network running.
Before you install, know this about the package
We opened the official 30.2 DEB package so you don't get surprised. Its postinst script makes up a random admin key, stores it in the ini at /etc/typesense/typesense-server.ini, and starts the server straight away. That ini tells Typesense to listen on every IPv4 address (0.0.0.0) on port 8108, and the package leaves it readable by all local users until the install block tightens it to 600 a few seconds later (nobody else has a login on a fresh server). The typesense-server.service unit has no User= line, so Typesense runs as root.
Up and running in an evening
Log in, become root with sudo -i, and paste the block below. It refreshes apt and installs ufw and curl, turns ufw on with only SSH allowed, fetches the newest release for your processor (amd64 or arm64), installs it, locks the config file to root, moves Typesense onto 127.0.0.1 so only this machine can reach it, saves the admin key in a root-only curl settings file (/root/.typesense-admin.curl) for the commands further down, and waits until it reports healthy. That is every way it departs from the official install guide, plus --force-confold, which keeps your edited config through later upgrades. If SSH answers on a port other than the standard one, open it with ufw allow 2222/tcp (your number instead of 2222) before pasting, since the OpenSSH profile covers just port 22.
apt-get update && apt-get install -y ufw curl \
&& sed -i 's/^IPV6=.*/IPV6=yes/' /etc/default/ufw && ufw allow OpenSSH && ufw --force enable \
&& V=$(curl -fsS https://api.github.com/repos/typesense/typesense/releases/latest | sed -n 's/.*"tag_name": *"v\([0-9.]*\)".*/\1/p') \
&& [ -n "$V" ] && A=$(dpkg --print-architecture) && P=/root/typesense-pkg/typesense-server-$V-$A.deb \
&& install -d -m 700 /root/typesense-pkg \
&& curl -fL -o "$P" "https://dl.typesense.org/releases/$V/typesense-server-$V-$A.deb" \
&& apt-get install -y -o Dpkg::Options::=--force-confold "$P" \
&& I=/etc/typesense/typesense-server.ini && chmod 600 "$I" \
&& sed -i 's/^api-address *=.*/api-address = 127.0.0.1/' "$I" && grep -qx 'api-address = 127.0.0.1' "$I" \
&& K=$(sed -n 's/^api-key *= *//p' "$I") && [ -n "$K" ] && C=/root/.typesense-admin.curl \
&& install -m 600 /dev/null "$C" \
&& printf 'header = "X-TYPESENSE-API-KEY: %s"\nheader = "Content-Type: application/json"\n' "$K" > "$C" \
&& systemctl enable --now typesense-server && systemctl restart typesense-server \
&& { ok=; for i in $(seq 1 30); do curl -fs http://127.0.0.1:8108/health >/dev/null && ok=1 && break; sleep 2; done; [ -n "$ok" ]; } \
&& ss -ltn | grep -q ' 127.0.0.1:8108 ' && ! ss -ltn | grep -q ' 0.0.0.0:8108 ' \
&& echo "Typesense $V answers on 127.0.0.1:8108 only" \
|| echo "STOP - read the message above; nothing after the failed step ran; check ufw status before going on"
When STOP appears, the steps after the one that broke never ran. Do what the message says, look at ufw status, then paste the block again. A second run leaves your config and key alone; if a newer Typesense is out by then, though, it upgrades you, so read its release notes first.
Prefer containers? Map the official image's port as 127.0.0.1:8108:8108, not the 8108:8108 of the install guide's Compose file, because IPv4 traffic to a port Docker publishes never meets ufw's rules; from Engine 28 on, Docker keeps a 127.0.0.1 mapping local. Swap the sample key xyz for a real one as well.
Letting visitors search, safely
The key in the ini can do everything, including deleting your collections, and the server configuration docs warn against putting it in browser code. Make a search-only key for the browser instead.
- As root, ask Typesense for a key that can only search your collection (swap
catalogfor its name) by runningcurl -fsS http://127.0.0.1:8108/keys -K /root/.typesense-admin.curl -d '{"actions":["documents:search"],"collections":["catalog"],"description":"browser search"}'; curl picks up the admin key from/root/.typesense-admin.curl. Copy thevaluefrom the answer now; it is not shown again. - If your own backend on this server makes the searches, you are done. If visitors' browsers will talk to Typesense themselves, set up a DNS name for this server, then let web traffic in (
ufw allow 80,443/tcp) ahead of any certificate request. - Install Caddy (
apt-get update, thenapt-get install -y caddy, from the universe repository on Ubuntu 24.04), give it your name withprintf '%s {\n reverse_proxy 127.0.0.1:8108\n}\n' search.yourshop.example > /etc/caddy/Caddyfile, thencaddy validate --adapter caddyfile --config /etc/caddy/Caddyfile && systemctl restart caddy. Caddy fetches and renews the certificate for you. - Tell Typesense which site may query it from the browser by adding
enable-cors = truepluscors-domains = https://www.yourshop.exampleto the ini (no slash at the end), thensystemctl restart typesense-server.
Who can still see the admin key? Root, through the ini and /root/.typesense-admin.curl, and anyone who can open your backup archives, since they include it. Setting expires_at on the keys you hand out lets you rotate them on a schedule.
A nightly copy you can actually restore
Copying /var/lib/typesense while it runs can catch files mid-write, which the backup guide calls unsafe, so ask Typesense for a snapshot and archive that. Wait until your first collection holds documents before running it. It saves a small script, runs it, and only after that first success schedules it for 03:30 server time every night.
cat > /usr/local/sbin/typesense-backup.sh <<'EOF'
set -eu -o pipefail
umask 077
B=/var/backups/typesense; T=$(date +%F-%H%M%S); W="$B/work-$T"; F="$B/.part-$T"
trap 'rm -rf "$W" "$F"' EXIT
curl -fsS -K /root/.typesense-admin.curl -X POST \
"http://127.0.0.1:8108/operations/snapshot?snapshot_path=$W/data" | grep -q '"success":true'
tar -czf "$F" -C "$W" data -C /etc/typesense typesense-server.ini
tar -tzf "$F" > "$W/list"
grep -qx typesense-server.ini "$W/list"; grep -q '^data/state/snapshot/' "$W/list"
mv "$F" "$B/typesense-$T.tar.gz"
find "$B" -maxdepth 1 -name 'typesense-*.tar.gz' -mtime +14 -delete
echo "backup OK $B/typesense-$T.tar.gz"
EOF
install -d -m 700 /var/backups/typesense && bash /usr/local/sbin/typesense-backup.sh \
&& printf 'SHELL=/bin/bash\n30 3 * * * root bash /usr/local/sbin/typesense-backup.sh > /var/backups/typesense/last-run.log 2>&1\n' > /etc/cron.d/typesense-backup \
&& echo "nightly backup scheduled" || echo "STOP - no archive was kept and no job was installed; read the message above"
Each run packs the config file into the archive, checks the archive's contents, and clears out archives past their fourteenth day only once the new one has checked out. The archives hold your admin key, so they stay private to root. Copy them to another machine too, using rsync -a without --delete, so a mistake here can't wipe the copies.
If you need to go back
Put the archive's path in A (see them with ls /var/backups/typesense) and paste as root. Before touching the service it checks the archive and makes sure no older set-aside folder is in the way; it then saves a rollback script and moves your current data to /var/lib/typesense.previous instead of deleting it.
cat > /root/ts-rollback.sh <<'EOF'
D=/var/lib/typesense
test -d "$D.previous" && test ! -e "$D.failed" && systemctl stop typesense-server \
&& { test ! -e "$D" || mv "$D" "$D.failed"; } && mv "$D.previous" "$D" && systemctl start typesense-server \
&& echo "rolled back" || echo "STOP - check which of $D, $D.previous and $D.failed exist before going on"
EOF
A=/var/backups/typesense/typesense-2026-11-01-033000.tar.gz; D=/var/lib/typesense; G=
test -f "$A" && gzip -t "$A" && tar -tzf "$A" > /root/ts-restore.list \
&& grep -q '^data/state/snapshot/' /root/ts-restore.list && test -d "$D" && test ! -e "$D.previous" \
&& G=1 || echo "STOP - the archive check failed, $D is missing or $D.previous already exists; nothing was touched"
[ -n "$G" ] && { systemctl stop typesense-server \
&& mv "$D" "$D.previous" && install -d -m 755 "$D" && tar -xzf "$A" -C "$D" --strip-components=1 data \
&& systemctl start typesense-server \
&& { ok=; for i in $(seq 1 120); do curl -fs http://127.0.0.1:8108/health >/dev/null && ok=1 && break; sleep 5; done; [ -n "$ok" ]; } \
&& echo "restored from $A - check your collections" \
|| echo "STOP - if $D.previous does not exist, your data was not moved and nothing is lost (run systemctl start typesense-server if it is stopped); if it does, your old data is there, so read journalctl -u typesense-server and /var/log/typesense/typesense.log; if it is still loading, wait and check /health again, otherwise run bash /root/ts-rollback.sh"; }
Big indexes take a while to rebuild, and the loop gives up after ten minutes (the updating guide quotes 5 to 60 minutes of downtime when Typesense Cloud upgrades a lone node), so if the log says Typesense is still loading, give it time and check /health again. If the restored data is wrong, bash /root/ts-rollback.sh puts your previous data back. When all looks right, delete the .previous folder, since any later restore halts at its first check while it exists. After a rollback, delete .failed as well, or the next rollback refuses. /root/ts-restore.list is just a listing; delete it whenever you like.
Moving to a new server? Run the install block there first. Search keys you made travel with the data (auth_manager.cpp keeps them in the on-disk store); only the bootstrap key is new, and the archived ini holds the old one if your apps need it. Whenever the api-key line changes, including when you copy the old one back, rerun the install block, which restarts Typesense and refreshes /root/.typesense-admin.curl, which the nightly backup depends on. Skip that and each backup run is refused with a 401 you would only spot in /var/backups/typesense/last-run.log.
Keeping it current, and growing past one machine
Upgrading means installing the newer package and restarting, and you never re-index, because Typesense rebuilds its indexes from the data on disk. Read what changed in each release from your version up to the target, as the updating guide asks, make an archive by running the backup script, and only then paste the install block once more. Your search is offline while the index reloads.
To avoid that pause, Typesense can run as a cluster of 3 nodes (survives one failure) or 5 (survives two, with slower writes), all sharing the bootstrap key. The nodes talk unencrypted, so the docs want them on private addresses; a private mesh, for example the one our NetBird workload page sets up, can give them those. Do the followers one by one and the leader last, letting /health answer on each before moving on; with the admin key, /debug shows state 1 on the leader and 4 on a follower.
Typesense is licensed GPL-3.0. Read this as our general view rather than legal advice. Using it for your own search, changed or unchanged, asks nothing of you; handing copies to anyone else, changed or unchanged, means handing over the source too, under GPL-3.0 again. Unlike the AGPL, it has no clause for software offered over a network.
When this isn't the right fit
- Your index won't fit in one server's memory. Every cluster node keeps the whole dataset, so more nodes give you safety, not room.
- You lean on built-in embedding models. They work on a processor, but the docs report a marked improvement on a GPU, and only Nvidia GPUs are supported.
Questions people ask
- Is self-hosting Typesense free?
- The software is open source under GPL-3.0, with no licence to pay for. What you pay for is the machine, sized by memory.
- What happens when Typesense runs out of memory?
- Its
/healthendpoint adds aresource_errorofOUT_OF_MEMORY(orOUT_OF_DISK). You can make it refuse writes before that point withmemory-used-max-percentagein the ini; the default of 100 never refuses. Watch memory through/metrics.jsonand keep it under 85%. - Do I need three servers?
- Not to start. One server with nightly snapshot archives copied elsewhere is a sound setup for many sites. Typesense calls a highly available cluster optional but highly recommended for production; 3 nodes survive one failure and 5 survive two, and a single node also goes offline during every upgrade.