Store data with SQLite

Give your agent a place to save data that sticks around
View as Markdown

Every agent gets its own storage space at /data — a folder that keeps its contents even after your agent restarts. Anything you save there is still there next time.

SQLite is a simple way to use that space. It’s a small database that lives in a single file, with no separate server to run. Save the file under /data and your agent can remember things: past conversations, user preferences, notes, counters — whatever you need.

You don’t have to set anything up. The /data folder is always there, with 5 GB of space by default. Want more space or a different location? See Change the size or location.

Save data with SQLite

Open a database file inside /data and use it like any other database. The folder is already there and ready to write to. The examples below use Python and Node, but the same idea works in any language with a SQLite library — point the file at /data.

1

Add a SQLite library

Nothing to install — Python’s sqlite3 module is built in.

2

Create a small storage helper

Put all your database code in one file. It opens the database in /data, creates the table the first time it runs, and gives the rest of your agent two simple functions: remember() and recent().

store.py
1import sqlite3
2
3# Open (or create) the database in the persistent /data folder.
4# check_same_thread=False lets you reuse the connection across requests.
5conn = sqlite3.connect("/data/app.db", check_same_thread=False)
6conn.row_factory = sqlite3.Row # rows you can read by column name
7
8# Create the table the first time the agent runs. Safe to run every start.
9conn.execute(
10 """
11 CREATE TABLE IF NOT EXISTS messages (
12 id INTEGER PRIMARY KEY AUTOINCREMENT,
13 role TEXT NOT NULL,
14 content TEXT NOT NULL,
15 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
16 )
17 """
18)
19conn.commit()
20
21
22def remember(role: str, content: str) -> None:
23 """Save one message."""
24 conn.execute(
25 "INSERT INTO messages (role, content) VALUES (?, ?)",
26 (role, content),
27 )
28 conn.commit()
29
30
31def recent(limit: int = 20) -> list[sqlite3.Row]:
32 """Return the most recent messages, oldest first."""
33 rows = conn.execute(
34 "SELECT role, content FROM messages ORDER BY id DESC LIMIT ?",
35 (limit,),
36 ).fetchall()
37 return list(reversed(rows))
3

Use it in your agent

Import the helper and call remember() and recent() wherever your agent handles a message.

app.py
1from store import remember, recent
2
3
4def handle_message(user_text: str) -> str:
5 # Look at what was said before.
6 history = recent(limit=10)
7
8 # ... generate a reply using `history` and `user_text` ...
9 reply = generate_reply(history, user_text)
10
11 # Save both sides of the exchange for next time.
12 remember("user", user_text)
13 remember("assistant", reply)
14 return reply
4

Deploy

Deploy your agent the usual way — nothing extra to configure. The first time it runs, the database file is created. Every time after that, your data is already waiting.

$ast deploy

To confirm your data persists, send your agent a message so it calls remember(), then run ast deploy again (or restart the agent). Send another message: the earlier exchange should still come back from recent().

What sticks around, and what doesn’t

Only the /data folder is saved:

  • Inside /data — kept across restarts, crashes, and new deploys. Put your database here.
  • Anywhere else — wiped clean each time your agent restarts. A file saved outside /data won’t be there next time.

Always use a path that starts with /data. If you open a database with just a name like app.db, it’s saved outside /data and disappears when your agent restarts.

Your data is only deleted when you remove the agent completely. Deploying a new version keeps everything.

Change the size or location

The storage is 5 GB at /data by default. To change it, open Advanced sizing when you deploy or configure your agent:

  • Storage — choose how much space your agent gets. Pick this before your first deploy: once the agent is running, the size is locked and can’t be changed.
  • Mount path — change the folder if you prefer something other than /data. If you do, update the path in your code to match.

Good to know

If you run more than one copy of your agent at the same time, each copy gets its own separate storage — they don’t share data. SQLite is best when you run a single copy.

If you need several copies of your agent to share the same data, use a knowledge store (like Postgres or Redis) instead of a SQLite file. Otherwise, keep your agent at one copy.

A couple of habits that help:

  • Set up your tables on startup using CREATE TABLE IF NOT EXISTS … so a brand-new agent starts clean and an existing one keeps its data.
  • Back up by making a copy of the file, not by copying it while the agent is writing to it.

Going further

As your agent grows, these SQLite features are worth a look (all standard SQLite — nothing platform-specific):

  • Turn on WAL mode with PRAGMA journal_mode=WAL; right after opening the database. It lets reads and writes happen at the same time, which helps when your agent handles several requests at once.
  • Add indexes on columns you search or sort by often (CREATE INDEX …) to keep queries fast as your tables grow.
  • Search text with SQLite’s built-in full-text search (FTS5) — handy for finding past messages or notes by keyword.
  • Version your schema with a small migration step at startup (for example, track a version number with PRAGMA user_version) so you can safely change tables in a later release.
  • Store large files as files. For big attachments, save the file directly in /data and keep just its path in the database — databases are happiest with small rows.

Next steps