local-todo
v1.0.25
Published
Self-hosted local-todo: API + UI + embedded Postgres in one npm install
Readme
local-todo
Self-hosted todo / kanban / docs app you run on your own machine. The whole stack — API, UI, and an embedded Postgres database — ships in a single npm package. No Docker, no external database, no cloud account.
Quick start
npx local-todoOpen http://localhost:3001 and create your owner account. Ctrl+C stops it.
The first run downloads ~50 MB of Postgres binaries (one-time). Later runs start in a couple of seconds.
For a permanent command available on PATH:
npm install -g local-todo
local-todonvm users sometimes hit
command not found: local-todoafter a global install — it's a PATH issue specific to nvm.npx local-todois the reliable fallback.
Running it as a service
Three things you usually want from a self-hosted app: keep it running in the background, save your settings once, and have it start automatically on login. The CLI handles all three.
Background
local-todo start # detaches, returns immediately
local-todo status # is it running? what pid?
local-todo logs # last 100 lines of output
local-todo stop # clean shutdown (SIGINT)
local-todo restartSaved settings
local-todo reads ~/.local-todo/config on every launch and applies its
contents as environment variables. Shell-set env vars still win, so you can
override on a one-off run.
local-todo config set LOCAL_TODO_LAN 1 # advertise OAuth/MCP at LAN IP
local-todo config set PORT 4000
local-todo config list
local-todo config unset PORT
local-todo config clearAuto-start on login
local-todo enable # macOS: launchd; Linux: systemd user unit
local-todo disable # remove the serviceenable writes a service file that runs local-todo headlessly with your
saved config baked in. After enabling, the app boots whenever you log in and
restarts itself if it crashes.
- macOS service file:
~/Library/LaunchAgents/com.local-todo.plist - Linux service file:
~/.config/systemd/user/com.local-todo.service
If you change your config (local-todo config set ...) after enabling,
re-run local-todo enable to bake the new values into the service.
Sharing with another device on your LAN
The server already binds to all interfaces. Other devices on your LAN can hit
the URL printed at boot — for example http://192.168.1.42:3001. Plain UI
access works without any configuration on the host.
For OAuth or MCP clients (e.g. Claude Code) connecting from another device, the issuer URL must be reachable from that device. One-line setup:
local-todo config set LOCAL_TODO_LAN 1
local-todo restartThis is plain HTTP — fine on a trusted LAN, not OK over the open internet. Put a reverse proxy with TLS in front if you need to expose it more widely.
Where your data lives
| What | Path |
|---|---|
| Database, uploads, sessions | ~/.local-todo/pg/ |
| Saved config | ~/.local-todo/config |
| Run log | ~/.local-todo/local-todo.log |
| PID of the background instance | ~/.local-todo/local-todo.pid |
| Persisted JWT secret (sessions across restarts) | ~/.local-todo/.jwt-secret |
Back up ~/.local-todo/ to back up everything.
Updating
local-todo checks the npm registry once a day and prints a banner at boot
when a newer version is out. To install it:
local-todo stop
npm install -g local-todo@latest # or: npx local-todo (always uses latest)
local-todo startYour data survives upgrades. New database migrations run automatically on the first launch after the upgrade.
Wipe all data
local-todo disable # if you'd enabled the boot service
local-todo stop
rm -rf ~/.local-todo # delete every board, task, account, uploadThe next local-todo boot creates a fresh empty database.
Uninstalling
local-todo disable
local-todo stop
rm -rf ~/.local-todo # only delete if you really want the data gone
npm uninstall -g local-todo # if you installed globally
rm -rf ~/.npm/_npx # frees the cached Postgres binary (~50 MB)CLI flags
local-todo --version # print the installed version
local-todo --help # full command listConfiguration reference
All optional. Set as environment variables (or via config set).
| Variable | Default | Purpose |
|---|---|---|
| PORT | 3001 (or first free port) | HTTP port the app listens on |
| LOCAL_TODO_DATA_DIR | ~/.local-todo | Data directory |
| LOCAL_TODO_PG_PORT | 54329 | Embedded Postgres port |
| LOCAL_TODO_NO_BROWSER | unset | Set to 1 to skip auto-opening the browser |
| LOCAL_TODO_LAN | unset | Set to 1 to advertise OAuth/MCP at the host's LAN IP |
| DATABASE_URL | unset | Use your own Postgres instead of the embedded one |
| PUBLIC_BASE_URL / API_BASE_URL | localhost (or LAN IP if LOCAL_TODO_LAN=1) | UI/API origin used in absolute links and OAuth issuer |
| JWT_SECRET | persisted to ~/.local-todo/.jwt-secret | Override to set explicitly |
Requirements
- Node.js 20 or newer
- macOS, Linux, or Windows (Postgres binaries are auto-fetched per platform; auto-start service support is macOS + Linux for now)
