Gathering detailed insights and metrics for mutano
Gathering detailed insights and metrics for mutano
Gathering detailed insights and metrics for mutano
Gathering detailed insights and metrics for mutano
npm install mutano
Typescript
Module System
Node Version
NPM Version
TypeScript (100%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
17 Stars
51 Commits
1 Watchers
1 Branches
2 Contributors
Updated on Jun 24, 2025
Latest Version
2.6.5
Package Id
mutano@2.6.5
Unpacked Size
56.19 kB
Size
12.46 kB
File Count
5
NPM Version
10.9.2
Node Version
22.13.1
Published on
May 13, 2025
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
6
Converts Prisma/MySQL/PostgreSQL/SQLite schemas to Zod schemas, TypeScript interfaces, or Kysely type definitions
Install mutano
with npm
1npm install mutano
Create user table:
1CREATE TABLE `user` ( 2 `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 3 `name` varchar(255) NOT NULL COMMENT '@zod(z.string().min(10).max(255))', -- this will override the Zod type 4 `username` varchar(255) NOT NULL, 5 `password` varchar(255) NOT NULL, 6 `profile_picture` varchar(255) DEFAULT NULL, 7 `metadata` json NOT NULL COMMENT '@ts(Record<string, unknown>) @kysely(Record<string, string>)', -- this will override the TypeScript and Kysely type 8 `role` enum('admin','user') NOT NULL, 9 PRIMARY KEY (`id`) 10);
Use the mutano API:
1import { generate } from 'mutano' 2 3await generate({ 4 origin: { 5 type: 'mysql', 6 host: '127.0.0.1', 7 port: 3306, 8 user: 'root', 9 password: 'secret', 10 database: 'myapp', 11 overrideTypes: { 12 json: 'z.record(z.string())' 13 } 14 }, 15 destinations: [{ 16 type: 'zod', 17 useDateType: true, 18 useTrim: false, 19 nullish: false, // When true, nullable fields use nullish() instead of nullable() 20 folder: './generated', 21 suffix: 'schema' 22 }] 23})
1import { generate } from 'mutano' 2 3await generate({ 4 origin: { 5 type: 'mysql', 6 host: '127.0.0.1', 7 port: 3306, 8 user: 'root', 9 password: 'secret', 10 database: 'myapp', 11 overrideTypes: { 12 json: 'z.record(z.string())' 13 } 14 }, 15 destinations: [{ 16 type: 'ts', 17 modelType: 'type', // Generate TypeScript type aliases instead of interfaces 18 folder: './types', 19 suffix: 'types' 20 }] 21})
1import { generate } from 'mutano' 2 3await generate({ 4 origin: { 5 type: 'mysql', 6 host: '127.0.0.1', 7 port: 3306, 8 user: 'root', 9 password: 'secret', 10 database: 'myapp', 11 overrideTypes: { 12 json: 'z.record(z.string())' 13 } 14 }, 15 destinations: [{ 16 type: 'ts', 17 header: "import type { CustomType } from './types';\nimport type { BaseModel } from './models';" 18 }] 19})
1import { generate } from 'mutano' 2 3await generate({ 4 origin: { 5 type: 'mysql', 6 host: '127.0.0.1', 7 port: 3306, 8 user: 'root', 9 password: 'secret', 10 database: 'myapp', 11 overrideTypes: { 12 json: 'z.record(z.string())' 13 } 14 }, 15 destinations: [{ 16 type: 'zod', 17 header: "import { z } from 'zod';\nimport { CustomValidator } from './validators';" 18 }] 19})
1import { generate } from 'mutano' 2 3await generate({ 4 origin: { 5 type: 'mysql', 6 host: '127.0.0.1', 7 port: 3306, 8 user: 'root', 9 password: 'secret', 10 database: 'myapp', 11 overrideTypes: { 12 json: 'z.record(z.string())' 13 } 14 }, 15 destinations: [{ 16 type: 'kysely', 17 schemaName: 'Database', // Default is 'DB' 18 header: "import { Generated, ColumnType } from 'kysely';\nimport { CustomTypes } from './types';", 19 folder: './db/types', 20 suffix: 'db' 21 }] 22})
1import { generate } from 'mutano' 2 3// Generate without writing to disk 4const output = await generate({ 5 origin: { 6 type: 'mysql', 7 host: '127.0.0.1', 8 port: 3306, 9 user: 'root', 10 password: 'secret', 11 database: 'myapp' 12 }, 13 destinations: [{ 14 type: 'zod' 15 }], 16 dryRun: true // Return content and don't write to files 17}) 18 19// Output is an object where keys are filenames and values are file content 20console.log(Object.keys(output)) // ['user.ts', 'product.ts', ...] 21 22// You can access the content for a specific file 23console.log(output['user.ts'])
1import { generate } from 'mutano' 2 3await generate({ 4 origin: { 5 type: 'postgres', 6 host: '127.0.0.1', 7 port: 5432, 8 user: 'postgres', 9 password: 'secret', 10 database: 'myapp', 11 schema: 'public', // optional, defaults to 'public' 12 overrideTypes: { 13 jsonb: 'z.record(z.string())' 14 } 15 }, 16 destinations: [{ 17 type: 'zod', 18 useDateType: true 19 }] 20})
1import { generate } from 'mutano' 2 3await generate({ 4 origin: { 5 type: 'sqlite', 6 path: './myapp.db', 7 overrideTypes: { 8 json: 'z.record(z.string())' 9 } 10 }, 11 destinations: [{ 12 type: 'ts' 13 }] 14})
1import { generate } from 'mutano' 2 3await generate({ 4 origin: { 5 type: 'mysql', 6 host: '127.0.0.1', 7 port: 3306, 8 user: 'root', 9 password: 'secret', 10 database: 'myapp', 11 overrideTypes: { 12 json: 'z.record(z.string())' 13 } 14 }, 15 destinations: [ 16 { 17 type: 'zod', 18 useDateType: true, 19 folder: './generated/zod', 20 suffix: 'schema' 21 }, 22 { 23 type: 'ts', 24 folder: './generated/types', 25 suffix: 'type' 26 }, 27 { 28 type: 'kysely', 29 folder: './generated/kysely', 30 suffix: 'db' 31 } 32 ] 33})
This will generate all three types of output files for each table in your database, placing them in separate folders with appropriate suffixes.
The generator will create user.type.ts
, user.schema.ts
, and user.db.ts
files with the following contents:
1import { z } from 'zod'; 2import { CustomValidator } from './validators'; 3 4export const user = z.object({ 5 id: z.number().nonnegative(), 6 name: z.string().min(10).max(255), 7 username: z.string(), 8 password: z.string(), 9 profile_picture: z.string().nullable(), 10 role: z.enum(['admin', 'user']), 11}) 12 13export const insertable_user = z.object({ 14 name: z.string().min(10).max(255), 15 username: z.string(), 16 password: z.string(), 17 profile_picture: z.string().nullable(), 18 role: z.enum(['admin', 'user']), 19}) 20 21export const updateable_user = z.object({ 22 name: z.string().min(10).max(255).optional(), 23 username: z.string().optional(), 24 password: z.string().optional(), 25 profile_picture: z.string().nullable().optional(), 26 role: z.enum(['admin', 'user']).optional(), 27}) 28 29export const selectable_user = z.object({ 30 id: z.number().nonnegative(), 31 name: z.string(), 32 username: z.string(), 33 password: z.string(), 34 profile_picture: z.string().nullable(), 35 role: z.enum(['admin', 'user']), 36}) 37 38export type userType = z.infer<typeof user> 39export type InsertableUserType = z.infer<typeof insertable_user> 40export type UpdateableUserType = z.infer<typeof updateable_user> 41export type SelectableUserType = z.infer<typeof selectable_user>
1import { CustomType } from './types'; 2import { BaseModel } from './models'; 3 4// TypeScript interfaces for user 5 6export interface User { 7 id: number; 8 name: string; 9 username: string; 10 password: string; 11 profile_picture: string | null; 12 metadata: Record<string, unknown>; // Custom type from @ts comment 13 role: 'admin' | 'user'; 14} 15 16export interface InsertableUser { 17 name: string | null; // Optional because it has a default value 18 username: string; 19 password: string; 20 profile_picture: string | null; 21 metadata: Record<string, unknown>; // Custom type from @ts comment 22 role: 'admin' | 'user'; 23} 24 25export interface UpdateableUser { 26 name: string | null; // Optional for updates 27 username: string | null; // Optional for updates 28 password: string | null; // Optional for updates 29 profile_picture: string | null; 30 metadata: Record<string, unknown> | null; // Custom type from @ts comment, optional for updates 31 role: 'admin' | 'user' | null; // Optional for updates 32} 33 34export interface SelectableUser { 35 id: number; 36 name: string; 37 username: string; 38 password: string; 39 profile_picture: string | null; 40 metadata: Record<string, unknown>; // Custom type from @ts comment 41 role: 'admin' | 'user'; 42}
1import { Generated, ColumnType, Selectable, Insertable, Updateable } from 'kysely'; 2 3// JSON type definitions 4export type Json = ColumnType<JsonValue, string, string>; 5 6export type JsonArray = JsonValue[]; 7 8export type JsonObject = { 9 [x: string]: JsonValue | undefined; 10}; 11 12export type JsonPrimitive = boolean | number | string | null; 13 14export type JsonValue = JsonArray | JsonObject | JsonPrimitive; 15 16// Kysely type definitions for user 17 18// This interface defines the structure of the 'user' table 19export interface UserTable { 20 id: Generated<number>; 21 name: string; 22 username: string; 23 password: string; 24 profile_picture: string | null; 25 metadata: Record<string, unknown>; // Custom type from @kysely comment 26 role: 'admin' | 'user'; 27} 28 29// Define the database interface 30export interface DB { 31 user: UserTable; 32} 33 34// Use these types for inserting, selecting and updating the table 35export type User = Selectable<UserTable>; 36export type NewUser = Insertable<UserTable>; 37export type UserUpdate = Updateable<UserTable>;
1{ 2 "origin": { 3 "type": "mysql", 4 "host": "127.0.0.1", 5 "port": 3306, 6 "user": "root", 7 "password": "secret", 8 "database": "myapp", 9 "overrideTypes": { 10 "json": "z.record(z.string())" 11 }, 12 "ssl": { 13 "ca": "path/to/ca.pem", 14 "cert": "path/to/cert.pem", 15 "key": "path/to/key.pem" 16 }, 17 } | { 18 "type": "postgres", 19 "host": "127.0.0.1", 20 "port": 5432, 21 "user": "postgres", 22 "password": "secret", 23 "database": "myapp", 24 "schema": "public", 25 "overrideTypes": { 26 "jsonb": "z.record(z.string())" 27 }, 28 "ssl": { 29 "ca": "path/to/ca.pem", 30 "cert": "path/to/cert.pem", 31 "key": "path/to/key.pem" 32 }, 33 } | { 34 "type": "sqlite", 35 "path": "path/to/database.db", 36 "overrideTypes": { 37 "json": "z.record(z.string())" 38 } 39 } | { 40 "type": "prisma", 41 "path": "path/to/schema.prisma", 42 "overrideTypes": { 43 "Json": "z.record(z.string())" 44 } 45 }, 46 "destinations": [ 47 { 48 "type": "zod", 49 "useDateType": true, 50 "useTrim": false, 51 "nullish": false, // When true, nullable fields use nullish() instead of nullable() 52 "requiredString": false, // When true, adds min(1) validation to non-nullable string fields 53 "header": "import { z } from 'zod';\nimport { CustomValidator } from './validators';", 54 "folder": "@zod", 55 "suffix": "table" 56 }, 57 { 58 "type": "ts", 59 "enumType": "union", 60 "modelType": "interface", 61 "header": "import { CustomType } from './types';\nimport { BaseModel } from './models';", 62 "folder": "types", 63 "suffix": "type" 64 }, 65 { 66 "type": "kysely", 67 "schemaName": "Database", 68 "header": "import { Generated, ColumnType } from 'kysely';\nimport { CustomTypes } from './types';", 69 "outFile": "db.ts" 70 } 71 ], 72 "tables": ["user", "log"], 73 "ignore": ["log", "/^temp/"], 74 "camelCase": false, 75 "silent": false, 76 "dryRun": false, 77 "magicComments": true 78}
Option | Description |
---|---|
destinations | An array of destination configurations to generate multiple output formats from a single origin |
destinations[].type | The type of output to generate: "zod", "ts", or "kysely" |
destinations[].useDateType | (Zod only) Use a specialized Zod type for date-like fields instead of string |
destinations[].useTrim | (Zod only) Use z.string().trim() instead of z.string() |
destinations[].nullish | (Zod only) Use nullish() instead of nullable() for nullable fields. In updateable schemas, fields that were already nullable will become nullish |
destinations[].requiredString | (Zod only) Add min(1) for non-nullable string fields |
destinations[].enumType | (TypeScript only) How to represent enum types: "union" (default) or "enum" |
destinations[].modelType | (TypeScript only) How to represent models: "interface" (default) or "type" |
destinations[].schemaName | (Kysely only) Name of the database interface (default: "DB") |
destinations[].header | Custom header to include at the beginning of generated files (e.g., custom imports) |
destinations[].folder | Specify the output directory for the generated files |
destinations[].suffix | Suffix to the name of a generated file (eg: user.table.ts ) |
destinations[].outFile | (Kysely only) Specify the output file for the generated content. All tables will be written to this file |
tables | Filter the tables to include only those specified |
ignore | Filter the tables to exclude those specified. If a table name begins and ends with "/", it will be processed as a regular expression |
camelCase | Convert all table names and their properties to camelcase. (eg: profile_picture becomes profilePicture ) |
silent | Don't log anything to the console |
dryRun | When true, doesn't write files to disk but returns an object with filenames as keys and generated content as values |
magicComments | Use @zod and @ts comments to override types (unsupported by SQLite) |
You can override the default type for a specific column type. This is specific to each database type and is placed inside the origin object. Each database type has its own set of valid types that can be overridden:
1{ 2 "origin": { 3 "type": "mysql", 4 "host": "127.0.0.1", 5 "port": 3306, 6 "user": "root", 7 "password": "secret", 8 "database": "myapp", 9 "overrideTypes": { 10 "json": "z.record(z.string())", 11 "text": "z.string().max(1000)" 12 } 13 } 14}
1{ 2 "origin": { 3 "type": "postgres", 4 "host": "127.0.0.1", 5 "port": 5432, 6 "user": "postgres", 7 "password": "secret", 8 "database": "myapp", 9 "schema": "public", 10 "overrideTypes": { 11 "jsonb": "z.record(z.string())", 12 "uuid": "z.string().uuid()" 13 } 14 } 15}
1{ 2 "origin": { 3 "type": "sqlite", 4 "path": "./myapp.db", 5 "overrideTypes": { 6 "json": "z.record(z.string())", 7 "text": "z.string().max(1000)" 8 } 9 } 10}
1{ 2 "origin": { 3 "type": "prisma", 4 "path": "./schema.prisma", 5 "overrideTypes": { 6 "Json": "z.record(z.string())", 7 "String": "z.string().min(1)" 8 } 9 } 10}
You can use the @zod
comment to override the Zod type for a specific column. This is useful when you want to add custom validation or transformation to a field.
1CREATE TABLE `user` ( 2 `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 3 `name` varchar(255) NOT NULL COMMENT '@zod(z.string().min(10).max(255))', 4 `email` varchar(255) NOT NULL COMMENT '@zod(z.string().email())', 5 PRIMARY KEY (`id`) 6);
This will generate:
1export const user = z.object({ 2 id: z.number().nonnegative(), 3 name: z.string().min(10).max(255), 4 email: z.string().email(), 5})
You can use the @ts
comment to override the TypeScript type for a specific column. This is useful when you want to specify a more precise type for a field.
1CREATE TABLE `user` ( 2 `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 3 `metadata` json NOT NULL COMMENT '@ts(Record<string, unknown>)', 4 `settings` json NOT NULL COMMENT '@ts(UserSettings)', 5 PRIMARY KEY (`id`) 6);
This will generate:
1export interface User { 2 id: number; 3 metadata: Record<string, unknown>; 4 settings: UserSettings; 5}
You can use the @kysely
comment to override the Kysely type for a specific column. This is useful when you want to specify a more precise type for a field.
1CREATE TABLE `user` ( 2 `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 3 `metadata` json NOT NULL COMMENT '@kysely(Record<string, string>)', 4 PRIMARY KEY (`id`) 5);
This will generate:
1export interface UserTable { 2 id: Generated<number>; 3 metadata: Record<string, string>; 4}
You can use complex TypeScript types in the @ts
(or @kysely
) comment:
1CREATE TABLE `product` ( 2 `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 3 `variants` json NOT NULL COMMENT '@ts(Array<{ id: string; price: number; stock: number }>)', 4 PRIMARY KEY (`id`) 5);
This will generate:
1export interface Product { 2 id: number; 3 variants: Array<{ id: string; price: number; stock: number }>; 4}
No vulnerabilities found.
No security vulnerabilities found.