Persistence Database
Cascaide uses a database with a particular schema in order to implement state persistence. Currently only postgres is supported but will be expanded to more targets in upcoming versions. This is a set up guide, for understanding the schema itself, check out capabilities/persistence.
1. Quick DB Setup
If you don’t have a PostgreSQL database ready, choose one of these “5-minute” methods:
PGLite (Recommended)
For local development, the best option is to run a PGLite instance. This ships out of the box with all the starter projects, so you do not need separate database servers.
In the starter projects, if DATABASE_URL is not set, Cascaide automatically falls back to PGLite and
stores data in a local .cascaide_db directory.
If you’re doing this manually, you need to set up a a postgres.js-compatible client. All of that is
handled for you along with logging for development in lib/pglite.ts.
You can use the export from the above file to create your persistor.
Set DB_LOG=1 to see database lifecycle events in your terminal, or
DB_LOG=verbose for full query tracing.
Setting The Schema Up
We recommend you use PG Lite for local development. Otherwise, please follow this guide to set the schema up.
Prerequisites: You have an empty PostgreSQL database and a DATABASE_URL connection string ready.
Install Prisma
We use Prisma to manage the set up.
npm i prisma
npx prisma initThis will create the schema.prisma file. If you do not have a database url, you may follow the guide provided
by the terminal after these commands to set one up. Assuming you have your DATABASE_URL set up.
Define the Schema
Initialize your schema and define the essential Cascaide models in the schema.prisma file.
generator client {
provider = "prisma-client-js"
output = "../lib/generated/prisma"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum CascadeStatus {
RUNNING
COMPLETED
ERROR
}
enum ExecutionStatus {
RUNNING
COMPLETED
FAILED
}
model Cascade {
id String @id @default(uuid())
status CascadeStatus @default(RUNNING)
FnId Int @default(0) @map("fn_id")
userId String @map("user_id")
executions NodeExecution[]
contextEvents ContextEvent[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([userId, status])
@@map("cascades")
}
model NodeExecution {
id String @id @default(uuid())
nodeInstanceId String @unique @map("node_instance_id")
cascadeId String @map("cascade_id")
cascade Cascade @relation(fields: [cascadeId], references: [id], onDelete: Cascade)
nodeName String @map("node_name")
functionId Int @map("function_id")
inputContext Json @map("input_context")
fullOutput Json? @map("full_output")
location String
status ExecutionStatus @default(RUNNING)
error String?
startedAt DateTime @default(now()) @map("started_at")
completedAt DateTime? @map("completed_at")
@@unique([cascadeId, functionId])
@@map("node_executions")
}
model ContextEvent {
id Int @id @default(autoincrement())
key String
value Json
uiValue Json? @map("ui_value")
functionId Int @map("function_id")
cascadeId String @map("cascade_id")
cascade Cascade @relation(fields: [cascadeId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now()) @map("created_at")
@@index([cascadeId, functionId])
@@map("context_events")
}Push to Database
Sync your schema with the database and generate the Prisma client.
npx prisma db pushAfter this runs, your database will have the three tables above. The generated client will be at lib/generated/prisma.
Create SQL for Persistor
Set up your database connection using a singleton pattern to handle serverless environments or hot-reloads.
import postgres from 'postgres';
const connectionString = process.env.DATABASE_URL!;
const globalForSql = global as unknown as { sql: postgres.Sql<{}> };
export const sql = globalForSql.sql || postgres(connectionString, {
max: process.env.NODE_ENV === 'production' ? 10 : 1,
idle_timeout: 20,
connect_timeout: 10,
});
if (process.env.NODE_ENV !== 'production') globalForSql.sql = sql;You can now use this client to create the persistor. Check out the quickstart guides for steps.