SQL·Kotlin·Free

SQL to
Kotlin.

Turn a CREATE TABLE script into Kotlin data class models. One file per table, camelCase field names, nullable columns as Type? = null, and SQL enum types as @Serializable enum class. No ORM wiring, no annotations you did not ask for.

DDL·Kotlin·JVM·Package·MIT
payments.sqlInput
CREATE TYPE payment_method AS ENUM ('card', 'bank', 'wallet');

CREATE TABLE payments (
    id UUID PRIMARY KEY,
    amount DECIMAL(12, 2) NOT NULL,
    currency VARCHAR(3),
    method payment_method NOT NULL,
    created_at TIMESTAMP NOT NULL
);
compile
Payments.kt tsc cleanOutput
// Payments.kt
package com.example.payments

import kotlinx.serialization.Serializable

import java.util.UUID
import java.math.BigDecimal
import java.time.LocalDateTime
import kotlinx.serialization.Contextual

@Serializable
data class Payments(
    val id: @Contextual UUID,
    val amount: @Contextual BigDecimal,
    val currency: String? = null,
    val method: PaymentMethod,
    val createdAt: @Contextual LocalDateTime
)
What gets generated

Kotlin data classes. Nothing more.

Below: a small payments schema with an enum type, rendered to Kotlin. Each table becomes a @Serializable data class; each SQL ENUM becomes a @Serializable enum class. The output is model types — no table mapper, no query DSL, no entity manager.

// PaymentMethod.kt — enum type, one file
package com.example.payments

import kotlinx.serialization.Serializable
import kotlinx.serialization.SerialName

@Serializable
enum class PaymentMethod {
    @SerialName("card")
    CARD,
    @SerialName("bank")
    BANK,
    @SerialName("wallet")
    WALLET
}

// Payments.kt — table, one file
package com.example.payments

import kotlinx.serialization.Serializable

import java.util.UUID
import java.math.BigDecimal
import java.time.LocalDateTime
import kotlinx.serialization.Contextual

@Serializable
data class Payments(
    val id: @Contextual UUID,
    val amount: @Contextual BigDecimal,
    val currency: String? = null,
    val method: PaymentMethod,
    val createdAt: @Contextual LocalDateTime
)
Three things we get right

Grounded in how the DDL reads.

Each claim here is something you can verify by pasting your own schema into the converter. Click a card to see the DDL fragment that triggered it and the Kotlin that came out.

01Proofsnake_case columns become camelCase fields.Spec · InCode · Out
schema.sql fragment
CREATE TABLE employees (
    id INT PRIMARY KEY,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    email VARCHAR(150) UNIQUE NOT NULL,
    hire_date DATE NOT NULL,
    salary DECIMAL(10, 2),
    department_id INT NOT NULL
);
emitted Employees.kt
// Employees.kt
package com.example.models

import kotlinx.serialization.Serializable

import java.time.LocalDate
import java.math.BigDecimal
import kotlinx.serialization.Contextual

@Serializable
data class Employees(
    val id: Int,
    val firstName: String,
    val lastName: String,
    val email: String,
    val hireDate: LocalDate,
    val salary: @Contextual BigDecimal? = null,
    val departmentId: Int
)
Plain Kotlin

Data classes, ready to drop in.

One Kotlin data class per CREATE TABLE, inside a package you choose. No JPA annotations, no Exposed tables, no runtime you did not already have. The types are annotated for kotlinx.serialization; wire them to whatever DB layer your project already uses.

src/main/kotlin/com/example/models/ generated
// Departments.kt
package com.example.models

import kotlinx.serialization.Serializable

@Serializable
data class Departments(val id: Int, val name: String, val location: String? = null)

// Employees.kt
package com.example.models

import kotlinx.serialization.Serializable

import java.time.LocalDate
import java.math.BigDecimal
import kotlinx.serialization.Contextual

@Serializable
data class Employees(
    val id: Int,
    val firstName: String,
    val lastName: String,
    val email: String,
    val hireDate: LocalDate,
    val salary: @Contextual BigDecimal? = null,
    val departmentId: Int
)
Also available via MCP

Or ask Claude to do it.

The same generator ships as a Model Context Protocol server. It calls the same web API this converter uses, so the output is identical. Point Claude Desktop, Cursor, or any MCP-aware agent at a <code>.sql</code> file and it produces the Kotlin models as a diff — free, no token, no leaving the chat.

// claude-desktop config · .mcp.json
{
  "mcpServers": {
    "metaengine": {
      "command": "npx",
      "args": ["-y", "@metaengine/mcp-server"]
    }
  }
}

// Then in Claude:
// "Load db/schema.sql and generate Kotlin
//  models in package com.acme.domain."
See the MCP page
Questions

Things people ask.

The niche between "hand-writing model classes" and "pulling in an ORM" is thinly covered. Most of these answer what you actually get.

One Kotlin file per CREATE TABLE and one per CREATE TYPE ... AS ENUM, under a package you provide. The output is model types only — no query DSL, no table mappers, no repository layer. You get the data classes; you pick the data layer.

Try it on your own schema.

The converter runs in the browser. Your DDL never leaves the page.

Open the converter