Generate type-safe ReScript bindings from your Convex backend functions. This tool parses your Convex TypeScript code using the TypeScript AST and generates idiomatic ReScript modules with proper types and React hooks.
- π― Type-safe bindings - Generates fully typed ReScript modules from Convex functions
- π React hooks - Ready-to-use
useQueryanduseMutationhooks - π¦ Schema support - Parses Convex schema to generate document types
- π AST-based parsing - Uses TypeScript compiler API for accurate parsing
- β‘ Blazing fast - Powered by Bun runtime (10x faster than Node.js)
- ποΈ Watch mode - Auto-regenerate on file changes with @parcel/watcher
- π¨ Idiomatic ReScript - Generates clean, idiomatic ReScript code
- π‘οΈ Edge case handling - Handles reserved keywords, polymorphic variants
This package is designed to run with Bun for best performance:
# Recommended: Install with Bun
bun add -D convex-rescript-codegen
# Also works with npm/yarn/pnpm (requires Bun runtime)
npm install -D convex-rescript-codegenNote: This package requires Bun runtime to be installed on your system.
- Install Bun if you haven't already:
curl -fsSL https://bun.sh/install | bash- Add to your package.json scripts:
{
"scripts": {
"codegen": "bunx convex-rescript",
"codegen:watch": "bunx convex-rescript --watch"
}
}- Run the generator:
bun run codegen
# or directly with
bunx convex-rescript- Use the generated bindings:
// Your generated bindings are in src/bindings/generated/
open ConvexTypes
@react.component
let make = () => {
// Use generated query hook
let users = Convex_users.Query_list.use(~limit=Some(JSON.Encode.int(10)))
// Use generated mutation hook
let createUser = Convex_users.Mutation_create.use()
// Type-safe function calls
let handleCreate = async () => {
let userId = await createUser({
name: "Alice",
email: "alice@example.com"
})
Console.log2("Created:", userId)
}
// Render your UI...
}src/bindings/generated/
βββ ConvexTypes.res # Document types from schema
βββ ConvexBindings.res # Core Convex React bindings
βββ ConvexGenerated.res # Module exports
βββ Convex_users.res # Bindings for users.ts
βββ Convex_rooms.res # Bindings for rooms.ts
βββ Convex_messages.res # Bindings for messages.ts
convex-rescript [options]
Options:
-i, --input <path> Input directory (default: ./convex)
-o, --output <path> Output directory (default: ./src/bindings/generated)
-w, --watch Watch for changes
-v, --verbose Verbose output
-h, --help Show help# Basic usage (uses defaults)
convex-rescript
# Watch mode
convex-rescript --watch
# Custom paths
convex-rescript -i ./backend/convex -o ./frontend/src/bindings
# Verbose output for debugging
convex-rescript --verbose| Convex Type | ReScript Type |
|---|---|
v.string() |
string |
v.number() |
float |
v.boolean() |
bool |
v.null() |
unit |
v.id("table") |
tableId (e.g., usersId) |
v.optional(...) |
option<...> |
v.array(...) |
array<...> |
v.object(...) |
JSON.t |
v.any() |
JSON.t |
v.union(...) |
Polymorphic variants |
v.literal(...) |
Polymorphic variants |
module Query_list = {
type output = array<usersDoc>
@module("convex/react")
external useQuery: ('api, unit) => option<output> = "useQuery"
let use = () => {
useQuery(api["users"]["list"], ())
}
}module Query_getById = {
type input = {
userId: usersId,
}
type output = option<usersDoc>
@module("convex/react")
external useQuery: ('api, input) => option<output> = "useQuery"
let use = (~userId) => {
useQuery(api["users"]["getById"], {
userId: userId
})
}
}module Mutation_create = {
type input = {
name: string,
email: string,
avatar: option<string>,
}
type t = input => promise<usersId>
@module("convex/react")
external useMutation: 'api => t = "useMutation"
let use = () => {
useMutation(api["users"]["create"])
}
}type usersDoc = {
@as("_id") id: usersId,
@as("_creationTime") creationTime: float,
name: string,
email: string,
avatar: option<string>,
status: [| #online | #offline | #away],
lastSeen: float,
createdAt: float,
}The generator automatically escapes ReScript reserved keywords:
typeβtype_with@as("type")privateβ#"private"in polymorphic variants
Convex string unions are converted to ReScript polymorphic variants:
// Convex
status: v.union(
v.literal("online"),
v.literal("offline"),
v.literal("away")
)// ReScript
status: [| #online | #offline | #away]- Bun runtime 1.0+ (required) - Install Bun
- ReScript v11+ (tested with v12 RC)
- Convex backend with TypeScript functions
- React project (for the generated hooks)
- Complex nested types - Very complex nested object types default to
JSON.t - Function return types - Currently infers common patterns, not all return types
- Convex validators - Complex validator compositions may not be fully supported
- Actions - Limited support for Convex actions (treated similar to mutations)
- Full return type inference from function implementations
- Support for Convex HTTP endpoints
- Custom type mapping configuration
- Generate mock data for testing
- VS Code extension for instant generation
- Support for convex-helpers library patterns
MIT
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Built for the ReScript and Convex communities
- Inspired by GraphQL Code Generator and similar tools
- Uses ts-morph for robust TypeScript AST parsing
Made with β€οΈ for type-safe full-stack development