Skip to content

@venturekit/data

Terminal window
npm install @venturekit/data
import { createRdsConfig, DEFAULT_RDS_CONFIG, buildRdsConfig } from '@venturekit/data';
const config = createRdsConfig({ engine: 'postgres', instanceSize: 'small', databaseName: 'mydb' });
import { query, getPool, mapResults, mapRow } from '@venturekit/data';
const result = await query('SELECT * FROM tasks WHERE id = $1', [taskId]);
const tasks = mapResults(result, row => ({ id: row.id, title: row.title }));
import { beginTransaction, withTransaction, buildTransaction } from '@venturekit/data';
// Automatic commit/rollback
const result = await withTransaction(async (tx) => {
await tx.query('INSERT INTO tasks (title) VALUES ($1)', ['New']);
return { created: true };
});

Config helpers and the tool-agnostic dispatcher used by vk migrate:

import {
createMigrationConfig,
DEFAULT_MIGRATION_CONFIG,
getFlywayEnv,
} from '@venturekit/data';

@venturekit/data ships a pure-SQL migration runner that the CLI uses by default — files in db/migrations/ are applied in lexical order, one per transaction, tracked in the __vk_migrations table along with a content hash:

import {
runMigrations,
getMigrationStatus,
runSeeds,
getSeedStatus,
MIGRATIONS_TRACKING_TABLE, // '__vk_migrations'
SEEDS_TRACKING_TABLE, // '__vk_seeds'
} from '@venturekit/data';
await runMigrations({
config: createMigrationConfig(),
onApply: (entry) => console.log('applied', entry.filename),
});

Thrown by the migration runner — catch these in CI to fail loudly:

import {
MigrationToolNotImplementedError, // unsupported runner selected
MigrationHashMismatchError, // applied file was edited after the fact
MigrationCollisionError, // duplicate version across dirs
} from '@venturekit/data';

Hydrate DATABASE_URL from a Secrets Manager secret or an existing connection string at Lambda cold start:

import {
applyDatabaseUrlToEnv,
applyDbSecretToEnv,
} from '@venturekit/data';

The default row mapper converts snake_case columns to camelCase properties. Override globally if your schema uses a different convention:

import { configureMapper, getMapperConfig } from '@venturekit/data';
configureMapper({ rename: (col) => col }); // identity (no rename)

Wrap a request in runWithTenant() and every query inside it runs with the app.tenant_id / app.tenant_ids GUCs set, so Postgres row-level-security policies filter the rows your SQL forgot to — fail-closed:

import { runWithTenant, runWithTenantScope, runWithoutTenant } from '@venturekit/data';
await runWithTenant(tenantId, () => query('SELECT * FROM posts')); // only this tenant's rows
await runWithTenantScope([parentId, ...childIds], () => listReports()); // hierarchical read scope
await runWithoutTenant(() => listAllTenants()); // platform-level job

Set DB_TENANT_ROLE=app_user so scoped statements SET ROLE to a non-owner role — RLS does not apply to table owners or postgres (vk dev). @venturekit-pro/tenancy’s createTenantRlsMiddleware does the wrapping per request.

SubpathDescription
@venturekit/data/idempotencycreatePostgresIdempotencyStore() for the runtime’s idempotencyMiddleware + purgeExpiredIdempotencyRecords()
@venturekit/data/outboxappendToOutbox(), createPostgresOutboxStore() — the transactional-outbox store for relayOnce()
@venturekit/data/jobsQueryable Postgres job queue — enqueueJob, claimJobs, runJobsOnce, listJobs, reclaimStuckJobs
@venturekit/data/filesUpload metadata — recordFileObject, findFileObjectByChecksum, archiveFileObject, sweepArchivedFiles
@venturekit/data/flagsFeature flags with per-tenant / per-user pins and stable %-rollouts (createFlags, upsertFlag, setFlagOverride) + one JSONB settings document per tenant (getTenantSettings, setTenantSettings)
@venturekit/data/searchPure SQL builders — escaped ILIKE patterns, generated tsvector columns and websearch_to_tsquery fragments, keyset cursors. Nothing here runs a query

Each ships its migration (vk_data_00N_*.sql) in the package’s vk.migrations directory, which vk migrate auto-discovers (search has none). See the API reference.

import { createFlags } from '@venturekit/data/flags';
import { query } from '@venturekit/data';
const flags = createFlags({ querier: query }); // module scope — one snapshot per container, refreshed every 30 s
if (await flags.isEnabled('new-editor', { tenantId: ctx.tenant?.id, userId: ctx.user?.id })) { /* … */ }
  • RdsOutputs, RdsInfraConfig — RDS infrastructure types
  • Transaction, ResultsMapper — query and transaction types
  • RunOptions, RunResult, StatusEntry, SeedRunOptions — runner types
  • Querier, MapperOptions — mapper customisation types
  • Job, JobStatus, JobHandler, FileObject, OutboxRow, PostgresOutboxStore — subpath types
  • FeatureFlag, FeatureFlagOverride, FlagSubject, Flags, TenantSettingsOptions, KeysetCursor, FtsColumnOptions — flags and search types
  • @venturekit/core — required
  • pg — PostgreSQL client