http.session.sql
import http.session.sql
httpdoes not re-export this module, so it is reached only by importing it directly.
The session store that keeps sessions in a relational database.
It lives in its own submodule, rather than alongside the other stores,
so that a program using the default file store never loads the sql
module or any of its adapters.
import http
import http.session
import http.session.sql { SqlStore }
import sql
var store = SqlStore(sql.pool('postgres://localhost/app'))
store.migrate()
server.use(session.session({ store }))
Constants
DEFAULT_TABLE
http.session.sql.DEFAULT_TABLE = 'sessions'
Classes
SqlStore
class http.session.sql.SqlStore < SessionStore
Keeps sessions in one table of a relational database.
The table is three columns - the storage key, the payload, and when the
session stops being valid - and migrate() creates it on whichever
engine is in use.
What it takes
Either a sql.Connection or a sql.Pool. A server wants the pool: a
connection is used by one isolate at a time, and the pool is what hands
each request one and takes it back.
A connection belongs to the isolate that opened it and cannot be shared,
so under http.serve() each worker builds its own pool and its own
store inside setup, rather than being handed one from outside.
Concurrency
Every write is a single statement, so a reader never sees half a session. Two requests writing the same session at the same moment both succeed and the later one wins. Nothing here takes a lock.
- printable — has a
@to_string(), soechoandprint()show something useful
Constructor
http.session.sql.SqlStore(database, options: ?dict)
Parameters
database(Connection|Pool) — where the table livesoptions(?dict) —table(default'sessions') andgc_probability(default0.01)
Raises SessionError if the table name is not a plain identifier
SqlStore.table()
http.session.sql.SqlStore.table() -> string
The table sessions are kept in.
Returns string
SqlStore.migrate()
http.session.sql.SqlStore.migrate()
Creates the table and its index if they are not already there.
Safe to call on every start: an existing table is left exactly as it is, and nothing in it is touched.
The columns are portable rather than ideal for any one engine. An application that wants a different shape - a partitioned table, a different collation, an engine-specific TTL - creates the table itself and skips this.
| Column | Type | |
|---|---|---|
id | varchar(64) | the storage key, primary key |
payload | text | what the session holds |
expires_at | bigint | epoch seconds |
Returns — SqlStore: this same instance, for chaining
SqlStore.read()
http.session.sql.SqlStore.read(key: string)
SqlStore.write()
http.session.sql.SqlStore.write(key: string, payload: string, expires_at: number)
SqlStore.touch()
http.session.sql.SqlStore.touch(key: string, expires_at: number)
SqlStore.destroy()
http.session.sql.SqlStore.destroy(key: string)
SqlStore.gc()
http.session.sql.SqlStore.gc(now: number)
SqlStore.to_string()
http.session.sql.SqlStore.to_string()
2026, Richard Ore and Zuri contributors