Protobuf well-known types and their JSON form
In JSON a Timestamp is an RFC 3339 string such as "2026-09-25T14:30:00Z", a Duration is seconds with an s suffix such as "1.5s", an Any is an object with an "@type" URL beside the message's fields, and a wrapper such as Int32Value is the bare value. 64-bit integers are strings.
Updated
Well-known types
| Type | JSON form | Example |
|---|---|---|
Timestamp | RFC 3339 string. Written in UTC with Z and 0, 3, 6 or 9 fractional digits; offsets such as +03:00 are accepted when parsing | "2026-09-25T14:30:00.500Z" |
Duration | Seconds as a decimal with an s suffix, negative allowed | "300s", "1.500s", "-0.25s" |
Any | The packed message's JSON with an "@type" URL added. A well-known type inside Any goes under "value" | {"@type": "type.googleapis.com/shop.v1.Card", "number": "4242"} |
Struct | Any JSON object | {"team": "infra", "replicas": 3} |
Value | Any JSON value | 3, "x", true, null |
ListValue | A JSON array | [1, "two", null] |
NullValue | null | null |
Empty | An empty object | {} |
FieldMask | Comma-separated paths, each in lowerCamelCase | "displayName,address.city" |
Int32Value, UInt32Value, FloatValue, DoubleValue | The number itself; null means unset | 3, 0.5 |
Int64Value, UInt64Value | The number as a string | "9007199254740993" |
BoolValue, StringValue | The value itself | true, "hello" |
BytesValue | Base64 | "aGVsbG8=" |
Scalars and fields
| Proto | JSON |
|---|---|
int32, sint32, sfixed32, uint32, fixed32 | A number. Strings such as "5" are accepted |
int64, sint64, sfixed64, uint64, fixed64 | A string such as "5", since JavaScript numbers lose precision past 2^53. Numbers are accepted |
float, double | A number, or "NaN", "Infinity" or "-Infinity" |
bool | true or false |
string | A string |
bytes | Base64, standard with padding when written; URL-safe accepted |
| enum | The value's name, such as "ROLE_ADMIN". The number is accepted |
| message | An object |
repeated | An array |
map<K, V> | An object; keys are always strings, even for integer keys |
| field names | lowerCamelCase (run_at is runAt), or the json_name option. Parsers accept the original name too |
Worked example
A job message that uses five well-known types:
syntax = "proto3";
package jobs.v1;
import "google/protobuf/duration.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
message Job {
string name = 1;
google.protobuf.Timestamp run_at = 2;
google.protobuf.Duration timeout = 3;
google.protobuf.Int32Value retries = 4;
google.protobuf.FieldMask update_mask = 5;
google.protobuf.Struct labels = 6;
}And the JSON a client sends for it:
{
"name": "nightly-backup",
"runAt": "2026-09-25T02:00:00Z",
"timeout": "300s",
"retries": 3,
"updateMask": "runAt,timeout",
"labels": { "team": "infra", "critical": true }
}Fields left at their defaults can be left out: an absent retries is unset, which is exactly what the wrapper type is for. The .proto to JSON tool writes this skeleton from the message for you.
istek bundles the well-known types, so a .proto that imports google/protobuf/timestamp.proto loads with nothing installed. See istek.