This page provides a complete grammar reference for the proto3 language. Each section shows the formal grammar production using an EBNF-style notation, followed by examples.
This is a reference document. For a practical introduction to writing .proto files, see the Proto3 language guide .
Lexical elements
letter = "A" ... "Z" | "a" ... "z"
decimalDigit = "0" ... "9"
octalDigit = "0" ... "7"
hexDigit = "0" ... "9" | "A" ... "F" | "a" ... "f"
ident = letter { letter | decimalDigit | "_" }
fullIdent = ident { "." ident }
messageName = ident
enumName = ident
fieldName = ident
oneofName = ident
mapName = ident
serviceName = ident
rpcName = ident
messageType = [ "." ] { ident "." } messageName
enumType = [ "." ] { ident "." } enumName
Reserved keywords: syntax, import, weak, public, package, option, message, enum, service, rpc, returns, oneof, map, extensions, reserved, repeated, optional, required (proto2 only), to, max.
Integer and floating-point literals
intLit = decimalLit | octalLit | hexLit
decimalLit = ( "1" ... "9" ) { decimalDigit }
octalLit = "0" { octalDigit }
hexLit = "0" ( "x" | "X" ) hexDigit { hexDigit }
floatLit = ( decimals "." [ decimals ] [ exponent ]
| decimals exponent
| "." decimals [ exponent ] )
| "inf"
| "nan"
decimals = decimalDigit { decimalDigit }
exponent = ( "e" | "E" ) [ "+" | "-" ] decimals
strLit = ( "'" { charValue } "'" ) | ( '"' { charValue } '"' )
charValue = hexEscape | octEscape | charEscape | /[^\0\n\\]/
hexEscape = '\\' ( "x" | "X" ) hexDigit hexDigit
octEscape = '\\' octalDigit octalDigit octalDigit
charEscape = '\\' ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | '\\' | "'" | '"' )
File structure
proto = syntax { topLevelDef | emptyStatement }
topLevelDef = message | enum | extend | service | import | package | option
Every .proto file begins with a syntax declaration.
Syntax statement
syntax = "syntax" "=" ( "'proto3'" | '"proto3"' ) ";"
Import statement
import = "import" [ "weak" | "public" ] strLit ";"
import "google/protobuf/timestamp.proto" ;
import public "other/proto/public.proto" ;
import weak "experimental/feature.proto" ;
public re-exports the imported file: any file that imports this file also transitively imports the public import.
weak allows the import to fail silently (used for optional features).
Package statement
package = "package" fullIdent ";"
package com.example.myapp ;
The package name is used to avoid name collisions between message types and to generate appropriate namespaces in the target language.
Options
option = "option" optionName "=" constant ";"
optionName = ( ident | "(" fullIdent ")" ) { "." ( ident | "(" fullIdent ")" ) }
constant = fullIdent | ( [ "-" | "+" ] intLit ) | ( [ "-" | "+" ] floatLit )
| strLit | boolLit | MessageLiteralWithBraces
File-level options appear at the top level, outside any message or service definition: option java_package = "com.example.myapp" ;
option java_outer_classname = "MyProtos" ;
option java_multiple_files = true ;
option go_package = "github.com/example/myapp/proto" ;
option csharp_namespace = "Example.MyApp" ;
option objc_class_prefix = "MYA" ;
option optimize_for = SPEED ; // SPEED, CODE_SIZE, or LITE_RUNTIME
option cc_enable_arenas = true ;
message MyMessage {
string name = 1 [ deprecated = true ];
repeated int32 values = 2 [ packed = true ];
bytes data = 3 [ ctype = CORD ]; // C++ only
}
Custom options use extension syntax with a fully-qualified name in parentheses: import "google/protobuf/descriptor.proto" ;
extend google.protobuf.FieldOptions {
string my_field_option = 51234 ;
}
message MyMessage {
string name = 1 [ (my_field_option) = "hello" ];
}
Message definition
message = "message" messageName messageBody
messageBody = "{" { field | enum | message | option | oneof
| mapField | reserved | emptyStatement } "}"
Normal field
field = [ "repeated" | "optional" ] type fieldName "=" fieldNumber [ "[" fieldOptions "]" ] ";"
fieldOptions = fieldOption { "," fieldOption }
fieldOption = optionName "=" constant
fieldNumber = intLit
message SearchRequest {
string query = 1 ;
int32 page_number = 2 ;
int32 results_per_page = 3 ;
repeated string tags = 4 ;
optional string filter = 5 ;
}
Scalar field types
Proto type Notes Default double64-bit float 0float32-bit float 0int32Variable-length; inefficient for negative numbers 0int64Variable-length; inefficient for negative numbers 0uint32Variable-length unsigned 0uint64Variable-length unsigned 0sint32ZigZag-encoded; efficient for negative numbers 0sint64ZigZag-encoded; efficient for negative numbers 0fixed32Always 4 bytes; efficient if values > 2^28 0fixed64Always 8 bytes; efficient if values > 2^56 0sfixed32Always 4 bytes, signed 0sfixed64Always 8 bytes, signed 0booltrue or falsefalsestringUTF-8 or 7-bit ASCII ""bytesArbitrary byte sequence b""
Oneof
oneof = "oneof" oneofName "{" { option | oneofField | emptyStatement } "}"
oneofField = type fieldName "=" fieldNumber [ "[" fieldOptions "]" ] ";"
message SampleMessage {
oneof test_oneof {
string name = 4 ;
SubMessage sub_message = 9 ;
}
}
At most one field in a oneof can be set at any time. Setting a field in a oneof clears all other fields in the same oneof.
Map field
mapField = "map" "<" keyType "," type ">" mapName "=" fieldNumber
[ "[" fieldOptions "]" ] ";"
keyType = "int32" | "int64" | "uint32" | "uint64" | "sint32" | "sint64"
| "fixed32" | "fixed64" | "sfixed32" | "sfixed64"
| "bool" | "string"
message Project {
map < string , int32 > version_map = 1 ;
}
Reserved statements
reserved = "reserved" ( ranges | strFieldNames ) ";"
ranges = range { "," range }
range = intLit | ( intLit "to" ( intLit | "max" ) )
strFieldNames = strFieldName { "," strFieldName }
strFieldName = "'" ident "'" | '"' ident '"'
message Foo {
// Reserve field numbers 2, 15, and the range 9 through 11.
reserved 2 , 15 , 9 to 11 ;
// Reserve field names.
reserved "foo", "bar" ;
}
If a field number or name is reserved, it cannot be used in the message. This prevents accidental re-use when removing fields.
Enum definition
enum = "enum" enumName enumBody
enumBody = "{" { option | enumField | reserved | emptyStatement } "}"
enumField = ident "=" [ "-" ] intLit [ "[" enumValueOption { "," enumValueOption } "]" ] ";"
enumValueOption = optionName "=" constant
enum Status {
option allow_alias = true ;
STATUS_UNKNOWN = 0 ;
STATUS_STARTED = 1 ;
STATUS_RUNNING = 1 ; // Alias for STATUS_STARTED
STATUS_FINISHED = 2 ;
}
The first enum value must be zero in proto3.
allow_alias = true permits multiple enum values to share the same number.
Service definition
service = "service" serviceName "{" { option | rpc | emptyStatement } "}"
rpc = "rpc" rpcName "(" [ "stream" ] messageType ")"
"returns" "(" [ "stream" ] messageType ")"
( ( "{" { option | emptyStatement } "}" ) | ";" )
service SearchService {
// Unary RPC
rpc Search ( SearchRequest ) returns ( SearchResponse );
// Server streaming RPC
rpc ListResults ( SearchRequest ) returns ( stream SearchResponse );
// Client streaming RPC
rpc BatchSearch ( stream SearchRequest ) returns ( SearchResponse );
// Bidirectional streaming RPC
rpc BidiSearch ( stream SearchRequest ) returns ( stream SearchResponse );
}
Field numbers
Field numbers must be unique within a message. The valid range is 1 to 536,870,911 (2^29 - 1), but numbers 19000 through 19999 are reserved for the Protocol Buffers implementation.
Range Notes 1 – 15 Encode in one byte (use for frequently used fields). 16 – 2047 Encode in two bytes. 2048 – 536,870,911 Valid but use larger encoding. 19000 – 19999 Reserved for the Protocol Buffers implementation. Do not use.