Database Concepts
Supported databases, ORMs, and schema detection
No matter how many integrations you add, Corsair uses only four tables. This keeps your database clean and your queries fast.
Core Tables
corsair_providers
All integrations you have enabled.
-- Example row
id: "slack"
config: { ... }corsair_connections
The tenant connections for each integration. If multi-tenancy is off, this is 1:1 with providers.
-- Example rows
id: 1, tenant_id: "tenant_abc", provider_id: "slack", config: { botToken: "..." }
id: 2, tenant_id: "tenant_xyz", provider_id: "slack", config: { botToken: "..." }corsair_resources
Every piece of data from your integrations, cleaned up and constantly updated.
-- Example row
id: "uuid", tenant_id: "tenant_abc", resource: "slack", service: "messages"
resource_id: "msg_123", data: { text: "Hello!", channel: "C01234567" }When you send a Slack message, Corsair stores it here. When a webhook arrives saying the message was updated, Corsair updates this row. Your data is never stale.
corsair_events
A log of all events for replay and auditing.
-- Example rows
id: 1, resource_id: "msg_123", event_type: "created", ...
id: 2, resource_id: "msg_123", event_type: "updated", ...Want to see a message's history? Query this table to replay every change.
Querying Data
Use the Corsair ORM to query data with full type safety.
// Find a specific resource
const message = await corsair.slack.db.messages.findByResourceId("msg_123");
// List all messages for this tenant
const messages = await corsair.slack.db.messages.list({ limit: 50 });
// Search by data fields (JSONB)
const results = await corsair.slack.db.messages.search({
data: { channel: "C0123456789" },
limit: 20,
});
// Search with contains (LIKE)
const partialMatch = await corsair.slack.db.channels.search({
data: { name: { contains: "general" } },
});Foreign Keys
You can create foreign keys from your own tables to corsair_resources. Since Corsair keeps this data fresh through API calls and webhooks, your references always point to up-to-date data.
-- Your table
CREATE TABLE my_tickets (
id UUID PRIMARY KEY,
slack_message_id UUID REFERENCES corsair_resources(id),
...
);Database Configuration
Corsair connects directly to PostgreSQL. Pass either a pg Pool or a Kysely instance.
import { Pool } from "pg";
export const corsair = createCorsair({
database: new Pool({ connectionString: process.env.DATABASE_URL }),
plugins: [...],
});No Table Bloat
Adding more integrations doesn't add more tables. Slack, Linear, GitHub — they all use the same four tables. Your schema stays clean no matter how many integrations you add.
Next Steps
- PostgreSQL schema, indexes, and performance tips