TinyStore

Beyond one machine / The server

The server

When the chat runs on more than one machine, the programs on the other machines need to reach the store. tinystore serve serves a store's directory over TLS to clients that connect with a token. The clients use the same SDK and the same calls: only the open line changes.

Serve a store

sh
tinystore token new admin >> tokens.txt
tinystore token new data >> tokens.txt
tinystore serve ./data --listen tls://0.0.0.0:7443 --tls-cert cert.pem --tls-key key.pem --tokens tokens.txt

tinystore token new prints a line with a capability and a random token:

data hBVwqW1DHNHzhxCuwnzuCl6vSeta8REkKpp7M04IQ5k
CapabilityMay
adminanything, backups included
dataread and write the store
readcall only the methods the schema marks as reads; SQL only on a reader, no migrations

--listen tls:// refuses to start without a certificate, a key and a tokens file. The same server still serves programs on its own machine through its local socket or named pipe, which need no token: their permission is the file system's.

Connect

import { connect } from '@tinyshed/tinystore'

await using store = await connect('tls://db.internal:7443', { token: process.env.TINYSTORE_TOKEN! })
store = await tinystore.connect("tls://db.internal:7443", token=os.environ["TINYSTORE_TOKEN"])
store, err := tinystore.Connect(ctx, "tls://db.internal:7443", os.Getenv("TINYSTORE_TOKEN"))
// A Rust program runs the store in its own process: Store::open.

Every call after connect is the same as on a store opened locally. The client checks the server's certificate before the token leaves, so a token is never sent to a machine that only claims to be the server. A connection that drops is made again by the SDK; a subscription comes back with onMissed, and a worker's jobs return to the queue as a dead worker's would.

In a container

The release publishes an image, ghcr.io/tinyshed/tinystore, with the tinystore executable for amd64 and arm64:

sh
docker run -v /srv/chat:/data -p 7443:7443 ghcr.io/tinyshed/tinystore:0.1.0 \
  serve /data --listen tls://0.0.0.0:7443 --tls-cert /data/cert.pem --tls-key /data/key.pem --tokens /data/tokens.txt

On a terminal the server prints a banner and one line per event; anywhere else, in a container or a pipe, each line is a JSON object on stderr, ready for any log collector.

Look at it while it runs

The command line reads a store beside the server that holds it, without stopping it and without writing a byte:

sh
tinystore status ./data                        # what the store holds and who serves it
tinystore logs ./data -f                       # the application's logs as they arrive
tinystore sql ./data chat "select count(*) from messages"
tinystore backup ./data backups/now.zip
tinystore stop ./data                          # stop the server once its work is finished

Why this design?

Why a server is the same program as the sidecar. The sidecar that a Bun program starts on one machine and the server that other machines reach are the same tinystore serve with different listeners. A program tested against a private child, moved to a sidecar and then to a remote server runs the same core and the same protocol all the way.

Why tokens with three capabilities and nothing finer. Rules per bucket or per table become a policy language that nobody reads and everyone gets wrong. A store serves one application, so the useful lines are few: the application itself, a read-only dashboard or analyst, and the operator.

Why TLS by default. A token in clear text on a network is a token for anyone on that network. --listen tcp:// exists for a private network its operator trusts, and it sends the token as it is; everywhere else, use tls://, where the client checks the certificate before the token leaves.

See also

Edit this page on GitHub Updated 19 October 2026

esc
↑↓ navigate ↵ open ⇥ filter 0 results