Sql To Kysely

SQL DDL to Kysely TypeScript Database Interface Generator

Convert SQL CREATE TABLE DDL schemas into strongly-typed Kysely TypeScript database interfaces, Generated columns, and ColumnType definitions.

Presets:
Target Dialect:
Interface Casing:
Column Keys:
SQL CREATE TABLE DDLPostgreSQL
/**
 * Generated by ToolsAA SQL to Kysely TypeGen
 * Target Dialect: POSTGRES
 * Generated Tables: 4
 */

import type { ColumnType, Generated, Insertable, Selectable, Updateable } from 'kysely';


// ==========================================
// Enums & Custom Value Types
// ==========================================
export type UserRole = 'OWNER' | 'ADMIN' | 'MEMBER' | 'BILLING_CONTACT';
export type SubscriptionStatus = 'TRIALING' | 'ACTIVE' | 'PAST_DUE' | 'CANCELED' | 'INCOMPLETE';
export type InvoiceStatus = 'DRAFT' | 'OPEN' | 'PAID' | 'UNCOLLECTIBLE' | 'VOID';

// ==========================================
// Table Interfaces
// ==========================================
export interface OrganizationsTable {
  id: Generated<string>; // PRIMARY KEY | DEFAULT: gen_random_uuid()
  slug: string;
  name: string;
  settings: ColumnType<Record<string, unknown> | null, string | Record<string, unknown> | null, string | Record<string, unknown> | null | undefined>;
  is_active: Generated<boolean>; // DEFAULT: true
  created_at: Generated<Date>; // DEFAULT: CURRENT_TIMESTAMP
  updated_at: Generated<Date>; // DEFAULT: CURRENT_TIMESTAMP
}

export interface UsersTable {
  id: Generated<string>; // PRIMARY KEY | DEFAULT: gen_random_uuid()
  organization_id: string; // FK -> organizations.id
  email: string;
  full_name: string | null;
  role: Generated<UserRole>; // DEFAULT: MEMBER
  avatar_url: string | null;
  last_login_at: Date | null;
  created_at: Generated<Date>; // DEFAULT: CURRENT_TIMESTAMP
}

export interface SubscriptionsTable {
  id: Generated<string>; // PRIMARY KEY | DEFAULT: gen_random_uuid()
  organization_id: string; // FK -> organizations.id
  stripe_customer_id: string;
  stripe_subscription_id: string | null;
  plan_tier: Generated<string>; // DEFAULT: starter
  seat_count: Generated<number>; // DEFAULT: 5
  status: Generated<SubscriptionStatus>; // DEFAULT: TRIALING
  current_period_start: Date;
  current_period_end: Date;
  cancel_at_period_end: Generated<boolean>; // DEFAULT: false
  created_at: Generated<Date>; // DEFAULT: CURRENT_TIMESTAMP
}

export interface InvoicesTable {
  id: Generated<string>; // PRIMARY KEY | DEFAULT: gen_random_uuid()
  organization_id: string; // FK -> organizations.id
  subscription_id: string | null; // FK -> subscriptions.id
  invoice_number: string;
  subtotal_cents: Generated<number>; // DEFAULT: 0
  tax_cents: Generated<number>; // DEFAULT: 0
  total_cents: Generated<number>; // DEFAULT: 0
  currency: Generated<string>; // DEFAULT: USD
  status: Generated<InvoiceStatus>; // DEFAULT: OPEN
  paid_at: Date | null;
  line_items: ColumnType<Record<string, unknown>, string | Record<string, unknown>, string | Record<string, unknown> | undefined>;
  created_at: Generated<Date>; // DEFAULT: CURRENT_TIMESTAMP
}

// ==========================================
// Master Database Interface
// ==========================================
export interface Database {
  organizations: OrganizationsTable;
  users: UsersTable;
  subscriptions: SubscriptionsTable;
  invoices: InvoicesTable;
}

// ==========================================
// Convenience Entity Models (Select / Insert / Update)
// ==========================================
export type Organization = Selectable<OrganizationsTable>;
export type NewOrganization = Insertable<OrganizationsTable>;
export type OrganizationUpdate = Updateable<OrganizationsTable>;

export type User = Selectable<UsersTable>;
export type NewUser = Insertable<UsersTable>;
export type UserUpdate = Updateable<UsersTable>;

export type Subscription = Selectable<SubscriptionsTable>;
export type NewSubscription = Insertable<SubscriptionsTable>;
export type SubscriptionUpdate = Updateable<SubscriptionsTable>;

export type Invoic = Selectable<InvoicesTable>;
export type NewInvoic = Insertable<InvoicesTable>;
export type InvoicUpdate = Updateable<InvoicesTable>;
Tables Parsed4Independent schema models
Columns Converted38Typed schema attributes
Relations & KeysPostgreSQL
4Primary & foreign constraints

Zero-Upload Local Privacy

All SQL parsing and TypeScript schema synthesis execute 100% in your local browser sandbox. Your database architecture never leaves your machine.

Kysely Type-Safe Precision

Accurately maps SQL types to TypeScript, wrapping auto-increment and default values in Generated<T> and providing ColumnType definitions for complex data types.

Selectable, Insertable & Updateable

Automatically produces Selectable<Table>, Insertable<Table>, and Updateable<Table> helper types alongside the root Database interface ready for Kysely query builder.

Technical Reference & Architecture Guide

Sql To Kysely — Reference Guide

Comprehensive reference and type generation manual for converting SQL DDL schemas into end-to-end type-safe Kysely TypeScript interfaces across PostgreSQL, MySQL, and SQLite dialects.

Key Parameters & Controls

dialect'postgres' | 'mysql' | 'sqlite'

Target SQL database engine controlling dialect-specific data type translation and constraint syntax mapping.

Default: 'postgres'
variableCasing'pascal' | 'snake' | 'raw'

Casing strategy applied to generated TypeScript table interfaces and exported model type identifiers.

Default: 'pascal'
columnCasing'raw' | 'camel'

Field name transformation strategy for table properties to match either native SQL schema or Kysely CamelCasePlugin.

Default: 'raw'
outputTab'schema' | 'multifile' | 'relations' | 'config'

Structure of generated code, selecting between a single database.ts file, modular multi-file exports, relation types, or client config.

Default: 'schema'

Pro Tips & Best Practices

Handling Auto-Generated Columns

Ensure auto-increment, serial, and default-valued columns resolve to Kysely's Generated<T> or ColumnType<Select, Insert, Update>. This guarantees TypeScript enforces strict values on SELECT while keeping them optional on INSERT operations.

CamelCase Plugin Compatibility

When setting columnCasing to 'camel', register new Kysely({ plugins: [new CamelCasePlugin()] }) in your runtime setup. Without the runtime plugin, Kysely queries unquoted camelCase identifiers directly against the SQL engine, triggering column mismatch errors.

Dialect-Specific JSONB Types

For PostgreSQL JSONB or MySQL JSON columns mapped to unknown, override the generated interface with custom DTO types using ColumnType<UserMeta, string | UserMeta, string | UserMeta> to retain strong structural safety across inserts and queries.

Common Gotchas & Troubleshooting

PostgreSQL TIMESTAMPTZ serializes to string instead of Date in runtime queries

Kysely reflects the runtime driver's behavior. Configure pg.types.setTypeParser(1184, (val) => new Date(val)) or override the column definition with ColumnType<Date, string | Date, string | Date> to support both ISO strings on insert and Date instances on select.

Runtime column does not exist error when querying tables with columnCasing set to camel

If columnCasing is set to camel, Kysely generates camelCase property keys. You must register CamelCasePlugin when initializing your Kysely database instance (new Kysely({ plugins: [new CamelCasePlugin()] })), otherwise queries will send camelCase names directly to SQL.

Frequently Asked Questions

Does Sql To Kysely transmit proprietary SQL schemas or table definitions to external servers?▼

No. All SQL parsing, AST traversal, dialect analysis, and TypeScript interface generation run strictly in client-side memory within your browser sandbox. No DDL statements, table schemas, or metadata are transmitted over the network.

How are composite primary keys structured in the generated TypeScript output?▼

Composite primary keys are identified from multi-column PRIMARY KEY constraints and mapped as non-nullable columns in the corresponding table interface. Kysely does not require surrogate single keys; queries utilize tuple matching or compound filters such as db.selectFrom('table').where((eb) => eb.and([...])).

How does the generator handle custom PostgreSQL ENUM types and inline CHECK constraints?▼

PostgreSQL CREATE TYPE ... AS ENUM statements are parsed into exported TypeScript string union types (e.g., export type UserRole = 'admin' | 'user'). Inline CHECK constraints with value lists are similarly parsed into strict string literal unions for enhanced type safety.

What architectural differences exist between single schema and multifile export modes?▼

The schema mode exports a single database.ts containing all table interfaces, type aliases, and the root Database interface, suitable for smaller codebases. The multifile mode splits each entity into its own module under a tables/ directory and re-exports them via index.ts, avoiding monolithic merge conflicts in team environments.

Related Tools & Utilities

All Tools →