| id | urn:mif:go-htmx:how-to:deploy-with-litestream | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| type | procedural | ||||||||||||||
| created | 2026-07-12 00:00:00 UTC | ||||||||||||||
| namespace | go-htmx/docs/how-to | ||||||||||||||
| tags |
|
||||||||||||||
| title | How to deploy with Litestream, and drill a restore | ||||||||||||||
| temporal |
|
||||||||||||||
| relationships |
|
||||||||||||||
| provenance |
|
||||||||||||||
| modified | 2026-07-13T16:48:01.844Z |
When you're ready to run this app somewhere persistent and want the SQLite file protected against volume/instance loss, using this template's default durability story.
- An S3-compatible object storage bucket (or any Litestream-supported replica target) and credentials for it.
- The built binary (
just buildproducesbin/<name>) and thelitestreambinary on the host.
-
Set the environment variables
litestream.ymlreads:GO_HTMX_DB_PATH(or your renamed app's equivalent env prefix —just initrewrites this),LITESTREAM_S3_BUCKET,LITESTREAM_S3_PATH,LITESTREAM_S3_REGION,LITESTREAM_S3_ENDPOINT. -
Start replication as a sidecar process, alongside the app (not inside it — nothing in
internal/imports Litestream):litestream replicate -config litestream.yml
With any
LITESTREAM_*variable unset,litestream replicatefails outright on the unresolved environment substitution rather than silently running unreplicated — treat that failure as your deploy blocking on real config, not a bug to route around. -
Start the app binary normally (
./bin/<name>), pointed at the sameGO_HTMX_DB_PATHfilelitestream.ymlreplicates.
Before trusting this in production, prove the restore path works:
-
Stop the app and delete (or move aside) the local database file.
-
Restore from the replica:
litestream restore -config litestream.yml "$GO_HTMX_DB_PATH" -
Start the app again and confirm your data is back — e.g. reload the notes page and see the notes that existed before the deletion.
The restored database file matches what you had before the drill, and the app serves correctly from it.
Litestream keeps the "single SQLite file, single writer" contract unchanged because it replicates the WAL out-of-process. Two paths exist for outgrowing it — see Escalating beyond the defaults for LiteFS (multi-instance read replicas) and libSQL/Turso (managed, edge-hosted primary).