AstroCraft — home
AstroCraft
Buy a licence
All documentation

Bring a database

Two variables move accounts, invites, settings, drafts, snapshots and sessions into Turso/libSQL — and make the container disposable. Entirely optional.

Last updated

Everything else in these docs is the default, and nothing on this page changes it. If you never set these two variables, the store is the .accounts/ directory and you can skip this page entirely.

What it moves

Set them and the same store — accounts, invites, settings, drafts, snapshots, and Astro’s own sessions — moves into Turso/libSQL instead.

Variable What it is
ASTROCRAFT_DB_URL a libSQL URL: libsql://<db>-<org>.turso.io hosted, or file:/data/state.db for a local SQLite file
ASTROCRAFT_DB_TOKEN the database auth token. Hosted Turso needs it; a file: URL does not

Three commands to have one:

turso db create astrocraft
turso db show astrocraft --url          # → ASTROCRAFT_DB_URL
turso db tokens create astrocraft       # → ASTROCRAFT_DB_TOKEN

Nothing to migrate and no schema to apply — the table is created on first use.

Put them in the environment, not in .env

These two are read from process.env, by astro.config.mjs when it loads and by the accounts CLI under plain Node. A .env file reaches neither — Vite loads it into import.meta.env, which is where the Resend pair is read from and nowhere these are.

Verified by putting the URL in a .env and rebuilding: sessions stayed on the filesystem and the CLI wrote to .accounts/. A .env line would look like it worked and silently leave you on files.

Export them in the shell, or use your host’s environment UI.

Try it before an account is anywhere near it

ASTROCRAFT_DB_URL=file:/tmp/astrocraft.db \
  node --experimental-strip-types src/admin/js/accounts.cli.ts [email protected] "Your Name"

It prints where the record went, and it is not .accounts/.

There is no third state

Unset means the directory. Set means the database. Nothing detects, guesses or falls back.

A URL that cannot be reached or authenticated fails the first store touch with a sentence naming the variable, and deliberately does not revert to files. That is not strictness for its own sake: a deployment running against an empty store looks exactly like a fresh install, and a fresh install re-opens first-admin sign-up to whoever loads the page first.

An empty value counts as unset, and exactly one function owns both the read and that rule — so the store and the sessions can never disagree about whether there is a database.

A URL that does not even parse is reported as an unparseable URL and never echoed back to the screen.

What it actually buys

With the store in your database, the container’s volume holds only the checkout — which the entrypoint re-clones anyway. The machine becomes disposable: rebuild it, move it, run it somewhere else, and the accounts, the settings and everybody’s login survive. A redeploy no longer logs anybody out, and losing the volume costs you a clone rather than your accounts.

That is the whole of it, and it is why this is one variable rather than a feature.

Any other backing store

The accounts store is an unstorage namespace, so the same drivers Astro already uses for sessions — Cloudflare KV, Vercel KV, Netlify Blobs, Redis, S3 — drop in with one line in src/admin/js/accounts.ts. The database path above is the one that needs no line at all.

Troubleshooting

Set the variables and nothing changed. They are in a .env file. See above.

The CMS throws on first load naming both variables. The URL is unreachable or the token is wrong. It will not fall back, on purpose.

Sessions still reset on redeploy although accounts survive. The session driver is wired in your astro.config.mjs rather than by the integration — adapters claim that slot in their own setup hook and run first, so it has to be host config. Check the session line is present.

Everything works locally with a file: URL but not hosted. Hosted Turso needs ASTROCRAFT_DB_TOKEN; a file: URL does not, so this is the variable that goes missing.