NOML Specification
The complete reference for NoSQL Modeling Language
Version 1.0.0 — Firestore
Versioning & Format
| Current version | 1.0.0 |
| Version scheme | Semantic Versioning 2.0.0 — MAJOR.MINOR.PATCH |
| Document format | YAML 1.2 / JSON |
| Encoding | UTF-8 |
| File extension | .noml.yaml .noml.yml .noml.json |
| Target database | Firestore (MVP) — MongoDB, DynamoDB, etc. planned |
Design Principles
Lenient Parsing
Unknown fields are silently ignored. This allows forward compatibility and custom extensions.
Minimal Required Fields
Only version, database, and collections (with fields.type) are required. Everything else is optional.
Terminology
- Document
- A single record in a collection, analogous to a row in SQL.
- Collection
- A group of documents, analogous to a table in SQL.
- Subcollection
- A collection nested within a document.
- Field
- A named property of a document.
- Enum
- A set of predefined allowed values. Can include state machine transitions.
- Reference
- A field that points to another document in a different collection.
- Index
- A database structure that improves query performance, especially composite indexes in Firestore.
Required vs Optional
NOML requires only the minimum fields to produce a valid schema:
versionNOML version
databaseDatabase type
collectionsWith fields.type
Everything else — metadata, enums, keys, indexes, security, validation, label, description, etc. — is entirely optional.
Field Reference
Root — NomlSchema
| Field | Required | Type | Description |
|---|---|---|---|
| version | Required | string | NOML version (e.g. "1.0.0") |
| database | Required | string | Database type (e.g. "firestore") |
| collections | Required | Record<string, CollectionDef> | Collection definitions |
| metadata | Optional | MetadataDef | Project metadata |
| description | Optional | string | Schema description |
| updatedAt | Optional | string | Last update date (ISO 8601) |
| enums | Optional | Record<string, EnumDef> | Global enum definitions |
Metadata — MetadataDef
| Field | Required | Type | Description |
|---|---|---|---|
| name | Required | string | Schema/project name |
| description | Optional | string | Detailed description |
| author | Optional | string | Author or team name |
Collection — CollectionDef
| Field | Required | Type | Description |
|---|---|---|---|
| fields | Required | Record<string, FieldDef> | Field definitions |
| label | Optional | string | Logical name (e.g. Japanese name) |
| description | Optional | string | Collection description |
| path | Optional | string | Firestore path pattern (e.g. "users/{userId}") |
| keys | Optional | KeysDef | Key constraints (primary, foreign, unique) |
| subcollections | Optional | Record<string, CollectionDef> | Nested subcollection definitions |
| indexes | Optional | IndexDef[] | Composite index definitions |
| security | Optional | SecurityDef | Security rules |
Field — FieldDef
| Field | Required | Type | Description |
|---|---|---|---|
| type | Required | string | Field data type (Firestore type or enum name) |
| label | Optional | string | Logical name (e.g. Japanese name) |
| description | Optional | string | Field description |
| required | Optional | boolean | Whether field is required (default: false) |
| nullable | Optional | boolean | Whether null is allowed |
| default | Optional | any | Default value |
| example | Optional | any | Example value for documentation |
| source | Optional | string | Data source (e.g. "documentId") |
| immutable | Optional | boolean | Cannot be updated after creation |
| autoUpdate | Optional | boolean | Auto-update on each write |
| target | Optional | string | Target collection for reference type |
| items | Optional | string | object | Array item type definition |
| fields | Optional | Record<string, FieldDef> | Nested fields for map type |
| validation | Optional | ValidationDef | Validation constraints |
| denormalizedFrom | Optional | object | string | Source of denormalized data |
| denormalization | Optional | object | Denormalization targets and sync method |
Enum — EnumDef
| Field | Required | Type | Description |
|---|---|---|---|
| values | Required | array | Allowed values (strings, numbers, or objects with value/label/description) |
| label | Optional | string | Logical name |
| description | Optional | string | Enum description |
| transitions | Optional | Record<string, string[]> | State machine transitions (from → to[]) |
Use the enum name directly as the field type:
enums:
UserRole:
values: [user, admin, moderator]
collections:
users:
fields:
role:
type: UserRole # enum name as type
default: userKeys — KeysDef
| Field | Required | Type | Description |
|---|---|---|---|
| primary | Optional | string | Primary key field name |
| description | Optional | string | Keys description |
| foreign | Optional | ForeignKeyDef[] | Foreign key definitions (field, references, onDelete) |
| unique | Optional | UniqueKeyDef[] | Unique key definitions (field, enforceBy) |
| compositeUnique | Optional | CompositeUniqueDef[] | Composite unique key definitions (fields, enforceBy) |
Index — IndexDef
| Field | Required | Type | Description |
|---|---|---|---|
| fields | Required | IndexFieldDef[] | Fields to index (field, order, arrayContains) |
| name | Optional | string | Index name |
| description | Optional | string | Index description |
| queryExample | Optional | string | Example query using this index |
Security — SecurityDef
| Field | Required | Type | Description |
|---|---|---|---|
| read | Optional | SecurityRuleDef[] | Read operation rules (condition, description, excludeFields) |
| create | Optional | SecurityRuleDef[] | Create operation rules |
| update | Optional | SecurityRuleDef[] | Update operation rules |
| delete | Optional | SecurityRuleDef[] | Delete operation rules |
Validation — ValidationDef
| Field | Required | Type | Description |
|---|---|---|---|
| min | Optional | number | Minimum value (for number) |
| max | Optional | number | Maximum value (for number) |
| minLength | Optional | number | Minimum string length |
| maxLength | Optional | number | Maximum string length |
| pattern | Optional | string | Regex pattern |
| format | Optional | string | Predefined format (email, url, uuid, date, phone) |
| minItems | Optional | number | Minimum array length |
| maxItems | Optional | number | Maximum array length |
| enum | Optional | array | Inline allowed values (use global enums instead) |
Denormalization
NoSQL databases often denormalize data for read performance. NOML supports documenting both the source and destination of denormalized data.
denormalization — Source field
displayName:
type: string
denormalization:
targets:
- collection: posts
field: authorName
syncMethod: cloudFunctiondenormalizedFrom — Destination field
authorName:
type: string
denormalizedFrom:
collection: users
field: displayNameData Types
| Type | Description | Example |
|---|---|---|
| string | Text data | "Hello" |
| number | Integer or float | 42, 3.14 |
| boolean | True or false | true |
| timestamp | Date and time | 2024-01-15T10:30:00Z |
| geopoint | Geographic coordinates | { lat: 35.67, lng: 139.65 } |
| reference | Document reference | /users/abc123 |
| array | Ordered list | ["a", "b", "c"] |
| map | Nested object | { key: "value" } |
Special Values
| Value | Description | Usage |
|---|---|---|
| serverTimestamp | Server-generated timestamp | default: serverTimestamp |
| autoId | Auto-generated document ID | default: autoId |
Specification Extensions
Vendor-specific extensions must use the x- prefix. Unknown fields are silently ignored.
collections:
users:
x-firebase-ttl: 86400
fields:
email:
type: string
x-algolia-searchable: true
secretKey:
type: string
x-sensitive: true
x-encryption: AES-256Full Example
A complete NOML document using all major features — metadata, enums with transitions, collections, subcollections, references, keys, indexes, validation, security, and denormalization.
version: "1.0.0"
database: firestore
metadata:
name: Blog Platform
description: A full-featured blog with users, posts, and comments
author: Platform Team
enums:
UserRole:
label: ユーザー権限
description: User permission levels
values:
- value: user
label: User
description: Regular user
- value: admin
label: Administrator
PostStatus:
label: 投稿ステータス
values: [draft, review, published, archived]
transitions:
draft: [review, archived]
review: [draft, published]
published: [archived]
archived: []
collections:
users:
label: ユーザー
description: Registered user accounts
keys:
primary: id
unique:
- field: email
enforceBy: cloudFunction
fields:
id:
type: string
source: documentId
required: true
email:
type: string
label: メールアドレス
required: true
immutable: true
validation:
format: email
displayName:
type: string
label: 表示名
required: true
validation:
maxLength: 100
denormalization:
targets:
- collection: posts
field: authorName
syncMethod: cloudFunction
role:
type: UserRole
label: 権限
default: user
createdAt:
type: timestamp
label: 作成日時
default: serverTimestamp
immutable: true
subcollections:
settings:
label: 設定
description: User preferences
fields:
theme:
type: string
label: テーマ
default: system
language:
type: string
default: en
security:
read:
- condition: "request.auth != null"
description: Authenticated users can read
update:
- condition: "request.auth.uid == resource.data.id"
description: Users can update their own profile
excludeFields: [role, createdAt]
posts:
label: 投稿
description: Blog posts
keys:
foreign:
- field: authorId
references: users.id
onDelete: cascade
fields:
title:
type: string
label: タイトル
required: true
validation:
maxLength: 200
authorId:
type: string
required: true
immutable: true
authorName:
type: string
label: 著者名
denormalizedFrom:
collection: users
field: displayName
tags:
type: array
label: タグ
items: string
validation:
maxItems: 10
status:
type: PostStatus
label: ステータス
default: draft
createdAt:
type: timestamp
default: serverTimestamp
immutable: true
indexes:
- name: posts_by_author
fields:
- authorId
- field: createdAt
order: desc
- name: posts_by_tag
fields:
- field: tags
arrayContains: true
- field: createdAt
order: descTry it in the viewer
Write your NOML and see it visualized instantly.
Open Viewer