Introduction¶
Not all constraints to an fstab file can be modeled using JSON Schema alone; however, it can represent a good number of them and the exercise is useful to demonstrate how constraints work. The examples provided are illustrative of the JSON Schema concepts rather than a real, working schema for an fstab file.
This example shows a possible JSON Schema representation of file system mount points as represented in an /etc/fstab file.
An entry in an fstab file can have many different forms; Here is an example:
data
1
{2
"/": {3
"storage": {4
"type": "disk",5
"device": "/dev/sda1"6
},7
"fstype": "btrfs",8
"readonly": true9
},10
"/var": {11
"storage": {12
"type": "disk",13
"label": "8f3ba6f4-5c70-46ec-83af-0d5434953e5f"14
},15
"fstype": "ext4",16
"options": [ "nosuid" ]17
},18
"/tmp": {19
"storage": {20
"type": "tmpfs",21
"sizeInMB": 6422
}23
},24
"/var/www": {25
"storage": {26
"type": "nfs",27
"server": "my.nfs.server",28
"remotePath": "/exports/mypath"29
}30
}31
}Creating the fstab schema¶
We will start with a base JSON Schema expressing the following constraints:
- the list of entries is a JSON object;
- the member names (or property names) of this object must all be valid, absolute paths;
- there must be an entry for the root filesystem (ie,
/).
Building out our JSON Schema from top to bottom:
- The
$id keyword. - The
$schema keyword. - The
type validation keyword. - The
required validation keyword. - The
properties validation keyword.
- The
/ key is empty now; We will fill it out later.
- The
patternProperties validation keyword.
- This matches other property names via a regular expression. Note: it does not match
/. - The
^(/[^/]+)+$ key is empty now; We will fill it out later.
- The
additionalProperties validation keyword.
- The value here is
false to constrain object properties to be either / or to match the regular expression.
You will notice that the regular expression is explicitly anchored (with ^ and $): in JSON Schema, regular expressions (in patternProperties and in pattern) are not anchored by default.

schema
1
{2
"$id": "https://example.com/fstab",3
"$schema": "https://json-schema.org/draft/2020-12/schema",4
"type": "object",5
"required": [ "/" ],6
"properties": {7
"/": {}8
},9
"patternProperties": {10
"^(/[^/]+)+$": {}11
},12
"additionalProperties": false13
}Starting the entry schema¶
We will start with an outline of the JSON schema which adds new concepts to what we've already demonstrated.
We saw these keywords in the prior exercise: $id, $schema, type, required and properties.
To this we add:
- The
description annotation keyword. - The
oneOf keyword. - The
$ref keyword.
- In this case, all references used are local to the schema using a relative fragment URI (
#/...).
- The
$defs keyword.
- Including several key names which we will define later.

schema
1
{2
"$id": "https://example.com/entry-schema",3
"$schema": "https://json-schema.org/draft/2020-12/schema",4
"description": "JSON Schema for an fstab entry",5
"type": "object",6
"required": [ "storage" ],7
"properties": {8
"storage": {9
"type": "object",10
"oneOf": [11
{ "$ref": "#/$defs/diskDevice" },12
{ "$ref": "#/$defs/diskUUID" },13
{ "$ref": "#/$defs/nfs" },14
{ "$ref": "#/$defs/tmpfs" }15
]16
}17
},18
"$defs": {19
"diskDevice": {},20
"diskUUID": {},21
"nfs": {},22
"tmpfs": {}23
}24
}Constraining an entry¶
Let's now extend this skeleton to add constraints to some of the properties.
- Our
fstype key uses the enum validation keyword. - Our
options key uses the following:
- The
type validation keyword (see above). - The
minItems validation keyword. - The
items validation keyword. - The
uniqueItems validation keyword. - Together these say:
options must be an array, and the items therein must be strings, there must be at least one item, and all items should be unique.
- We have a
readonly key.
With these added constraints, the schema now looks like this:

schema
1
{2
"$id": "https://example.com/entry-schema",3
"$schema": "https://json-schema.org/draft/2020-12/schema",4
"description": "JSON Schema for an fstab entry",5
"type": "object",6
"required": [ "storage" ],7
"properties": {8
"storage": {9
"type": "object",10
"oneOf": [11
{ "$ref": "#/$defs/diskDevice" },12
{ "$ref": "#/$defs/diskUUID" },13
{ "$ref": "#/$defs/nfs" },14
{ "$ref": "#/$defs/tmpfs" }15
]16
},17
"fstype": {18
"enum": [ "ext3", "ext4", "btrfs" ]19
},20
"options": {21
"type": "array",22
"minItems": 1,23
"items": {24
"type": "string"25
},26
"uniqueItems": true27
},28
"readonly": {29
"type": "boolean"30
}31
},32
"$defs": {33
"diskDevice": {},34
"diskUUID": {},35
"nfs": {},36
"tmpfs": {}37
}38
}The diskDevice definition¶
One new keyword is introduced here:
- The
pattern validation keyword notes the device key must be an absolute path starting with /dev.
data
1
{2
"diskDevice": {3
"properties": {4
"type": {5
"enum": [ "disk" ]6
},7
"device": {8
"type": "string",9
"pattern": "^/dev/[^/]+(/[^/]+)*$"10
}11
},12
"required": [ "type", "device" ],13
"additionalProperties": false14
}15
}The diskUUID definition¶
No new keywords are introduced here.
We do have a new key: label and the pattern validation keyword states it must be a valid UUID.
data
1
{2
"diskUUID": {3
"properties": {4
"type": {5
"enum": [ "disk" ]6
},7
"label": {8
"type": "string",9
"pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"10
}11
},12
"required": [ "type", "label" ],13
"additionalProperties": false14
}15
}The nfs definition¶
We find another new keyword:
- The
format annotation and assertion keyword.
data
1
{2
"nfs": {3
"properties": {4
"type": { "enum": [ "nfs" ] },5
"remotePath": {6
"type": "string",7
"pattern": "^(/[^/]+)+$"8
},9
"server": {10
"type": "string",11
"oneOf": [12
{ "format": "hostname" },13
{ "format": "ipv4" },14
{ "format": "ipv6" }15
]16
}17
},18
"required": [ "type", "server", "remotePath" ],19
"additionalProperties": false20
}21
}The tmpfs definition¶
Our last definition introduces two new keywords:
- The
minimum validation keyword. - The
maximum validation keyword. - Together these require the size be between 16 and 512, inclusive.
data
1
{2
"tmpfs": {3
"properties": {4
"type": { "enum": [ "tmpfs" ] },5
"sizeInMB": {6
"type": "integer",7
"minimum": 16,8
"maximum": 5129
}10
},11
"required": [ "type", "sizeInMB" ],12
"additionalProperties": false13
}14
}The full entry schema¶
The resulting schema is quite large:

schema
1
{2
"$id": "https://example.com/entry-schema",3
"$schema": "https://json-schema.org/draft/2020-12/schema",4
"description": "JSON Schema for an fstab entry",5
"type": "object",6
"required": [ "storage" ],7
"properties": {8
"storage": {9
"type": "object",10
"oneOf": [11
{ "$ref": "#/$defs/diskDevice" },12
{ "$ref": "#/$defs/diskUUID" },13
{ "$ref": "#/$defs/nfs" },14
{ "$ref": "#/$defs/tmpfs" }15
]16
},17
"fstype": {18
"enum": [ "ext3", "ext4", "btrfs" ]19
},20
"options": {21
"type": "array",22
"minItems": 1,23
"items": {24
"type": "string"25
},26
"uniqueItems": true27
},28
"readonly": {29
"type": "boolean"30
}31
},32
"$defs": {33
"diskDevice": {34
"properties": {35
"type": {36
"enum": [ "disk" ]37
},38
"device": {39
"type": "string",40
"pattern": "^/dev/[^/]+(/[^/]+)*$"41
}42
},43
"required": [ "type", "device" ],44
"additionalProperties": false45
},46
"diskUUID": {47
"properties": {48
"type": {49
"enum": [ "disk" ]50
},51
"label": {52
"type": "string",53
"pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"54
}55
},56
"required": [ "type", "label" ],57
"additionalProperties": false58
},59
"nfs": {60
"properties": {61
"type": { "enum": [ "nfs" ] },62
"remotePath": {63
"type": "string",64
"pattern": "^(/[^/]+)+$"65
},66
"server": {67
"type": "string",68
"oneOf": [69
{ "format": "hostname" },70
{ "format": "ipv4" },71
{ "format": "ipv6" }72
]73
}74
},75
"required": [ "type", "server", "remotePath" ],76
"additionalProperties": false77
},78
"tmpfs": {79
"properties": {80
"type": { "enum": [ "tmpfs" ] },81
"sizeInMB": {82
"type": "integer",83
"minimum": 16,84
"maximum": 51285
}86
},87
"required": [ "type", "sizeInMB" ],88
"additionalProperties": false89
}90
}91
}Referencing the entry schema in the fstab schema¶
Coming full circle we use the $ref keyword to add our entry schema into the keys left empty at the start of the exercise:
- The
/ key. - The
^(/[^/]+)+$ key.

schema
1
{2
"$id": "https://example.com/fstab",3
"$schema": "https://json-schema.org/draft/2020-12/schema",4
"type": "object",5
"required": [ "/" ],6
"properties": {7
"/": { "$ref": "https://example.com/entry-schema" }8
},9
"patternProperties": {10
"^(/[^/]+)+$": { "$ref": "https://example.com/entry-schema" }11
},12
"additionalProperties": false13
}