Skip to main content
typr— v1.0 RC6

Seal your system'sboundaries

Type‑safe code, generated for every boundary in your stack — databases, REST APIs, Avro topics, gRPC services. One domain type definition. The compiler enforces every contract.

Languages
Java · Kotlin · Scala 2/3
Boundaries
PostgreSQL · MariaDB · Oracle · SQL Server · DuckDB · DB2 · OpenAPI · Avro/Kafka · gRPC
Method
Schema → AST → typed code. No reflection. No runtime mapping.

Every system bug starts at a boundary.

Database to API. API to event bus. Event bus to RPC service. Each crossing is a translation, and every translation is an opportunity to drop, mistype, or quietly mangle a field.

Most teams paper over this with hand‑written DTOs, mapper classes, and a slow‑burning fear of refactoring. Typr takes the opposite approach: read the schema, generate the types, let the compiler enforce the boundary.

0102030405060708ABCDESECTION A — DOMAINfig. 01.ASECTION B — BOUNDARIESfig. 01.BDOMAIN TYPECustomercanonical01idCustomerId02firstNameFirstName03lastNameLastName04emailEmail?4 fieldsABOUNDARY · PRIMARYpostgresANCHORcustomer_id int4 PKfirst_name varcharlast_name varcharemail varchar?BBOUNDARY · ALIGNEDmariadbSUPERSETid bigint PKfirst_name varcharlast_name varcharemail text?CBOUNDARY · ALIGNEDopenapiEXACTcustomerId stringfirstName stringlastName stringemail string?DBOUNDARY · ALIGNEDkafkaSUBSETcustomerId stringfirstName stringlastName stringPRIMARYLEGENDanchor — primary sourceexact / superset alignmentsubset alignment (partial)UNIFIED TYPE / CUSTOMERDRAWING NO.typr.fig.01REVISIONRC6 / 2026.05SCALE1 : 1SHEET01 / 01
fig. 01One declaration of Customer, four boundaries, four alignment policies. The anchor (postgres) defines the shape; the others align — exact, superset, or subset — and Typr generates the mappers between them.

One ships. One never compiles.

Same feature. Same domain. Different consequences.

without typr

Long, Long, Long.

Every ID is a Long. Every name is a String. Mix them up and the compiler waves you through.

// API types (you write these)
record CreateOrderRequest(Long userId, BigDecimal amount) {}
record OrderResponse(Long id, Long userId, String status) {}

// DB types (you write these too)
record OrderEntity(Long id, Long userId, BigDecimal amount, String status) {}

// The mapper (you write this)
class OrderMapper {
OrderEntity toEntity(CreateOrderRequest req) {
return new OrderEntity(null, req.userId(), req.amount(), "pending");
}
OrderResponse toResponse(OrderEntity e) {
return new OrderResponse(e.id(), e.userId(), e.status());
}
}

class OrderService {
// BUG: userId and orderId are both Long — this compiles fine.
User getUser(Long orderId) {
return userRepository.findById(orderId);
}
}
with typr

UserId is not OrderId.

Generated distinct types. The compiler refuses the bug before it leaves your editor.

// Generated types — you write NOTHING.
// UserId, OrderId, OrderRow, OrderRowUnsaved,
// CreateOrderRequest, OrderResponse — all generated.

class OrderService {
OrderResponse createOrder(CreateOrderRequest req) {
OrderRow saved = orderRepo.insert(
new OrderRowUnsaved(req.userId(), req.amount()), conn);
return new OrderResponse(saved.id(), saved.userId(), saved.status());
}

// Won't compile: OrderId and UserId are different types.
User getUser(OrderId orderId) {
return userRepo.selectById(orderId);
// ^^^^^^^
// error: required UserId, found OrderId
}
}

The less context they have, the more the compiler matters.

New hires, contractors, AI agents — they don't carry your mental model. Typr gives them a working one, enforced.

01

Junior developers

Productive on day one.

Don't need the whole‑system map in their head. The types tell them what's possible — wrong ID type? wrong response shape? Won't compile.

02

Contractors

Limited blast radius.

Implement against a typed interface. They cannot accidentally break what they cannot touch. Safe delegation by construction.

03

AI agents

Constrained by the compiler.

Every type error is instant feedback. Fix, compile, fix, compile — tight loops save tokens and time. Guardrails outperform prompts.

04

Tech leads

Review contracts, not plumbing.

Approve schema and API changes — the implementation has to follow the types. High‑leverage decisions, low‑drag review.

Precision, not approximation.

Most generators flatten your contracts into the lowest common primitive. Typr preserves every distinction your schema cared enough to make.

schema source

Database column

declaredotherstypr
CHAR(50)StringPaddedString50
VARCHAR(100)StringVarcharMax100
users.id (PK)LongUserId
orders.user_id (FK)LongUserId
DEFAULT NOW()TimestampDefaulted<OffsetDateTime>
UUID[]Array<UUID>
composite typerecord / data class
schema source

OpenAPI spec

declaredotherstypr
200 / 404 responsesObjectsealed ADT
userId path paramStringUserId
nullable: trueTOptional<T> / T?
enum: [a, b, c]StringMyEnum
Server interfaceloose typesexact contract

Every boundary, one type system.

Add a second boundary and Typr validates that shared types stay consistent. Add a third and the validation compounds.

  1. 01

    Databases

    Schemas in. Repos out.

    Six engines: PostgreSQL, MariaDB, Oracle, SQL Server, DuckDB, DB2. Row types, ID types, repositories, type‑safe DSL queries. Full DDL fidelity — composite types, arrays, enums, domains, defaults.

    • 6 engines
    • DDL fidelity
    • Type‑safe DSL
    explore
  2. 02

    REST APIs

    OpenAPI as a contract.

    Sealed response types. Server stubs and client stubs that share the same interface. Same UserId in your handler as in your database row.

    • Sealed responses
    • Server + client
    • Shared types
    explore
  3. 03

    Events · Avro/Kafka

    Topics as types.

    Avro schemas in, typed producers and consumers out. Multi‑event topics with sealed interfaces. Built‑in Kafka RPC support — Spring, Quarkus, Cats Effect.

    • Avro codegen
    • Typed producers
    • Multi‑event topics
    explore
  4. 04

    gRPC · Protobuf

    Proto as a domain.

    Proto definitions map to your domain types with bidirectional, type‑safe converters. Enforced compatibility policies between proto and Java/Kotlin/Scala.

    • Proto codegen
    • Bidirectional
    • Type policies
    coming soon

Define Customer once. Use it everywhere.

Declare a domain type, anchor it to a primary boundary, and align other sources to it. Typr validates compatibility and generates every mapper.

  • Flow declarationsforward, drop, merge, split, computed
  • Type policiesexact · widen · narrow · nullable rules
  • Auto mappersfromX(...) and toX(...) per boundary
  • CI validationtypr check — fails on schema drift
Read the Unified Types spec
typr.yaml
# typr.yaml — define your domain once
domainTypes:
Customer:
primary: postgres:sales.customer # anchor boundary
fields:
id: CustomerId
firstName: FirstName
lastName: LastName
email: Email?
alignedSources:
mariadb:customers: superset # legacy DB
api:Customer: exact # OpenAPI contract
kafka:CustomerCreated: subset # event topic

# Optional: per-field type rules
fieldTypes:
CustomerId:
db: { column: [customer_id], primary_key: true }
FirstName:
db: { column: [first_name] }

Works with your stack.

Boundaries

  • PostgreSQL
  • MariaDB
  • Oracle
  • SQL Server
  • DuckDB
  • DB2
  • OpenAPI
  • Kafka / Avro
  • gRPC / Protobufsoon
  • GraphQLsoon

Languages

  • Java 17+
  • Kotlin
  • Scala 2
  • Scala 3

Frameworks

  • Spring Boot
  • Quarkus
  • Http4s
  • JAX‑RS
  • Cats Effect

Define your domain.
See the flow.
Ship with confidence.

Point typr at your schemas. Get back a typed surface for every boundary. Let the compiler do the work that used to live in your head.