A protoc plugin that generates SQL schema and CRUD query files from annotated protobuf definitions. Define your entities once in proto, generate schema for multiple database engines from a single source of truth.
npm install -g @protoutil/protoc-gen-sql
Add the options proto as a dependency in your buf.yaml:
- buf.build/protoutil/sql
1. Annotate your proto messages
import "protoutil/sql/v1/options.proto" ;
option (protoutil.sql.v1.message) = {
string name = 1 [(protoutil.sql.v1.field).omit = true ]; // derived at app layer
string email = 2 [(protoutil.sql.v1.field).unique = true ];
string bio = 3 [(protoutil.sql.v1.field).nullable = true ];
2. Configure buf.gen.yaml
3. Generate
This produces:
Passed via the opt: key in buf.gen.yaml. Each invocation targets one engine.
Option Required Values Default Description engineYes postgres mysql sqlite sqlserver— Target database engine repeated_strategyjson_column array_columnjson_columnHow repeated fields are stored oneof_strategynullable_columns type_column json_columnnullable_columnsDefault strategy for oneof groups if_not_existstrue falsetrueEmit IF NOT EXISTS in DDL emit_create_schematrue falsefalseEmit CREATE SCHEMA IF NOT EXISTS
Field Type Default Description generateboolfalseOpt this message into generation table_namestringFQN snake_case Override the generated table name indexesrepeated string[]Composite indexes as comma-separated column names unique_constraintsrepeated string[]Composite unique constraints skip_queriesrepeated QueryType[]Suppress specific generated queries foreign_keysrepeated ForeignKey[]Explicit FK column declarations timestampsTimestampBehaviorBOTHControls created_at / updated_at injection extra_columnsrepeated FieldOptions[]Additional columns with no proto field primary_keyPrimaryKeyTypePRIMARY_KEY_TYPE_SERIALStorage type for the id primary key column
Field Type Default Description column_namestringfield name Override the column name column_typestringengine default Override the SQL type type_overridesmap<string, string>{}Per-engine type overrides nullableboolfalseEmit NULL instead of NOT NULL defaultstring— SQL DEFAULT expression indexboolfalseAdd a single-column index uniqueboolfalseAdd a UNIQUE constraint omitboolfalseExclude this field entirely enum_strategyEnumStrategyENUM_STRATEGY_NAMEHow to store a proto enum field checkstring— Inline CHECK constraint skip_queriesrepeated QueryType[]Suppress this column from specific queries
Default proto scalar to SQL type per engine:
Proto type postgres mysql sqlite sqlserver stringTEXTTEXTTEXTNVARCHAR(MAX)boolBOOLEANTINYINT(1)INTEGERBITint32INTEGERINTINTEGERINTint64BIGINTBIGINTINTEGERBIGINTuint32BIGINTBIGINT UNSIGNEDINTEGERBIGINTuint64NUMERIC(20,0)BIGINT UNSIGNEDINTEGERDECIMAL(20,0)floatREALFLOATREALREALdoubleDOUBLE PRECISIONDOUBLEREALFLOATbytesBYTEABLOBBLOBVARBINARY(MAX)
Proto type postgres mysql sqlite sqlserver google.protobuf.TimestampTIMESTAMPTZDATETIME(6)TEXTDATETIMEOFFSETgoogle.protobuf.DurationBIGINTBIGINTINTEGERBIGINTgoogle.protobuf.StructJSONBJSONTEXTNVARCHAR(MAX)
Value Generated query QUERY_TYPE_GETSELECT ... WHERE id = $1 LIMIT 1QUERY_TYPE_LISTSELECT ... ORDER BY idQUERY_TYPE_CREATEINSERT INTO ...QUERY_TYPE_UPDATEUPDATE ... SET ... WHERE id = $1QUERY_TYPE_DELETEDELETE ... WHERE id = $1QUERY_TYPE_ALLSuppresses all query generation
Value created_atupdated_atBOTHInjected Injected CREATED_ONLYInjected Omitted UPDATED_ONLYOmitted Injected NONEOmitted Omitted
Value Behavior NULLABLE_COLSOne nullable column per variant + CHECK constraint TYPE_COLUMNDiscriminator column + single value column JSON_COLUMNEntire oneof serialized to a single JSON column
Value Behavior ENUM_STRATEGY_NAMEStore the enum value name as TEXT ENUM_STRATEGY_INTStore the integer value as INTEGER ENUM_STRATEGY_CHECK_CONSTRAINTStore as TEXT with CHECK constraint ENUM_STRATEGY_NATIVE_TYPEUse native database enum type (Postgres only)
Value Behavior PRIMARY_KEY_TYPE_SERIALEngine serial integer PRIMARY_KEY_TYPE_UUIDDatabase-generated UUID
Rule Description V01 foreign_key.column must not be emptyV02 foreign_key.references_table must not be emptyV03 FK column must not be a reserved column V04 FK column must not duplicate another column V05 extra_columns entry must have a non-empty column_nameV06 extra_columns entry must have a non-empty column_type or matching type_overridesV07 extra_columns entry must not have omit = trueV08 extra_columns column_name must not be a reserved columnV09 extra_columns column_name must not duplicate another columnV10 Indexed column names must exist in the table V11 Unique constraint column names must exist in the table V12 Field column_name override must not be a reserved column V13 Field column name must not duplicate another column V14 ENUM_STRATEGY_NATIVE_TYPE requires engine=postgresV15 type_overrides keys must be valid engine names