SQL to
Kotlin.
Turn a CREATE TABLE script into Kotlin model classes. One file per table, camelCase field names, nullable columns as Type?, and SQL enum types as real Kotlin enum class. No ORM wiring, no annotations you did not ask for.
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
);// Payments.kt
package com.example.payments
import java.util.UUID
import java.math.BigDecimal
import java.time.OffsetDateTime
import kotlinx.serialization.Contextual
class Payments {
val id: UUID
val amount: BigDecimal
val currency: String?
val method: PaymentMethod
val createdAt: @Contextual OffsetDateTime
}Plain Kotlin classes. Nothing more.
Below: a small payments schema with an enum type, rendered to Kotlin. Each table becomes a 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 java.util.UUID
import java.math.BigDecimal
import java.time.OffsetDateTime
import kotlinx.serialization.Contextual
class Payments {
val id: UUID
val amount: BigDecimal
val currency: String?
val method: PaymentMethod
val createdAt: @Contextual OffsetDateTime
}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.
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
);// Employees.kt
package com.example.models
import java.time.OffsetDateTime
import java.math.BigDecimal
import kotlinx.serialization.Contextual
class Employees {
val id: Int
val firstName: String
val lastName: String
val email: String
val hireDate: @Contextual OffsetDateTime
val salary: BigDecimal?
val departmentId: Int
}Model classes, ready to drop in.
One Kotlin class per CREATE TABLE, inside a package you choose. No JPA annotations, no Exposed tables, no runtime you did not already have. Wire them to whatever DB layer your project already uses.
// Departments.kt
package com.example.models
class Departments {
val id: Int
val name: String
val location: String?
}
// Employees.kt
package com.example.models
import java.time.OffsetDateTime
import java.math.BigDecimal
import kotlinx.serialization.Contextual
class Employees {
val id: Int
val firstName: String
val lastName: String
val email: String
val hireDate: @Contextual OffsetDateTime
val salary: BigDecimal?
val departmentId: Int
}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."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.
CREATE TABLE and one per CREATE TYPE ... AS ENUM, under a package you provide. The output is model classes only — no query DSL, no table mappers, no repository layer. You get the types; you pick the data layer.Try it on your own schema.
The converter runs in the browser. Your DDL never leaves the page.