Lix includes a lightweight, built-in logging system that writes structured data directly into Lix. This allows you to capture, query, and version logs alongside your application state, making them perfect for audit trails, debugging breadcrumbs, and collaborative session histories.
Add a log entry by inserting a row directly into the log table.
import { openLix } from "@lix-js/sdk";
const lix = await openLix({});
// The `id` and `timestamp` are automatically generated on insertion.
await lix.db
.insertInto("log")
.values({
key: "app_boot_success",
level: "info",
message: "Application booted and ready.",
payload: { version: "1.4.0", mode: "production" },
})
.execute();Use Lix for logs that are part of your application's state. Because logs are stored and versioned in the lix, they are queryable, shareable, and available long after the original process has exited.
| Use Lix Logging For... | Use console.log For... |
|---|---|
| User-facing logs (errors, activity) | Developer-only diagnostics |
| Persistent state to be queried & synced | Ephemeral data for immediate inspection |
| Testable application logic | Debugging the current execution |
Logs are stored in the log table and can be queried with the same Kysely API you use for other entities.
const recentErrors = await lix.db
.selectFrom("log")
.selectAll()
.where("level", "=", "error")
.orderBy("timestamp", "desc")
.limit(10)
.execute();Since logs are part of change control, you can inspect them at different points in history, diff them between commits, and sync them across clients.
A primary use case for Lix Logging is to create a queryable history of events that can be surfaced to end-users in your application's UI.
Instead of only logging errors to the console where they are lost, you can write them to Lix. This allows you to build an in-app "Error History" or "Activity" panel, giving users or support staff visibility into what went wrong.
1. Log an error when it occurs:
async function handleSubmit(formData) {
try {
await submitData(formData);
} catch (error) {
await createLog({
lix,
key: "form_submit_failed",
level: "error",
message: "Submission failed",
payload: { message: error.message, fields: Object.keys(formData) },
});
// Also notify the user immediately
}
}2. Query the logs to display in the UI:
You can create a React component, for example, that queries and displays all error logs.
function ErrorHistoryPanel({ lix }) {
const [errors, setErrors] = useState([]);
useEffect(() => {
const fetchErrors = async () => {
const result = await lix.db
.selectFrom("log")
.where("level", "=", "error")
.orderBy("timestamp", "desc")
.limit(50)
.selectAll()
.execute();
setErrors(result);
};
fetchErrors();
}, [lix]); // Re-run if lix instance changes
return (
<div>
<h3>Error History</h3>
<ul>
{errors.map((error) => (
<li key={error.id}>
<strong>{error.key}</strong>: {error.message ?? "No message"} (
{error.timestamp})
{error.payload ? (
<pre>{JSON.stringify(error.payload, null, 2)}</pre>
) : null}
</li>
))}
</ul>
</div>
);
}Because payload stores JSON, you can filter logs by payload fields using SQLite's json_extract helper through Kysely's sql tagged template.
import { sql } from "@lix-js/sdk";
const uploadFailures = await lix.db
.selectFrom("log")
.selectAll()
.where("level", "=", "error")
.where(sql`json_extract(payload, '$.operation')`, "=", "file_upload")
.where(sql`json_extract(payload, '$.retryable')`, "=", 1)
.orderBy("timestamp", "desc")
.execute();
// uploadFailures now contains only error logs whose payload.operation is "file_upload"
// and payload.retryable === true.snake_case keys: This makes filtering predictable (e.g., checkout_form_submit, checkout_form_error).info, warn, error, debug).log table grows. Prune it if it's not relevant to your test assertions to keep fixtures small.The default log table provides a minimal, effective schema.
| Column | Type | Description |
|---|---|---|
id | string | A unique identifier for the log entry. |
timestamp | string | ISO 8601 timestamp of when the log was created. |
key | string | A structured, snake_case key for filtering. |
level | string | The log level (e.g., info, error). |
message | string? | Optional descriptive message for the log. |
payload | JSON | Structured payload for storing queryable data. |