Formatting Guide

This guide defines how to keep VDL files easy to read, stable in diffs, and predictable across teams.

Note: These conventions are enforced by the official formatter. Run vdl format ./schema.vdl or use editor format-on-save through the VDL LSP.

1. General Principles

  • Format for consistency, not personal style.
  • Prefer the smallest readable layout.
  • Keep related items close; separate unrelated items with one blank line.
  • Use UTF-8, LF (\n), no trailing whitespace, and a final newline.

2. Indentation

  • Use 2 spaces per indentation level.
  • Do not use tabs.
type Example {
  field string
}

3. Top-Level Elements

Top-level elements are include, type, const, enum, comments, and standalone docstrings.

  • Group include statements at the top with no blank lines inside the group.
  • Use one blank line between top-level declarations.
  • Avoid multiple consecutive blank lines.
include "./common.vdl"
include "./auth.vdl"

const maxPageSize = 100

type Order {
  id string
  total float
}

enum OrderStatus {
  Pending
  Paid
}

4. Blocks and Fields

4.1 Block Structure

  • Put { on the same line as the declaration, with one space before it.
  • Put block members on their own lines.
  • Align } with the declaration start.
type User {
  id string
  name string
}

4.2 Field Members

  • Keep one member per line.
  • Prefer no blank lines between plain fields.
  • Add one blank line around field docstrings when it improves scanning.
  • Place spreads before regular fields when possible.
type User {
  ...AuditMetadata

  """ The user's display name. """
  name string

  """ The user's email address. """
  email string

  age? int
}

4.3 Annotation Placement

Annotations carry domain semantics. Keep placement strict and vertical for readability.

  • Put annotations directly above the declaration or member they target.
  • Use one annotation per line.
  • Keep docstring above annotations when both are present.
  • Keep a single blank line between logical groups of annotated members.
"""
User operations.
"""
@rpc
type Users {
  @proc
  GetUser {
    input {
      userId string
    }

    output {
      id string
      email string
    }
  }

  @stream
  UserEvents {
    input {
      userId string
    }
    output {
      event string
      at datetime
    }
  }
}

5. Spacing

ContextRuleExample
Field syntax<name>[?] <type>email? string
AssignmentOne space around =const retries = 3
Braces ({})One space before {type User {
Arrays ([])No spaces inside or before suffixstring[], int[][]
Maps (map[...])No spaces inside bracketsmap[int], map[User]
Annotation callNo space before (@meta({ owner "core" })
Object literal entriesSpace-separated key/value{ host "localhost" }
Array literal entriesSpace-separated elements["a" "b" "c"]
Enum member assignmentOne space around =Archived = "archived"

6. Comments

VDL supports two comment styles, and formatter preserves comment content exactly as written.

  • Single-line: // ...
  • Multi-line: /* ... */
  • Comments can appear at top level or inside blocks.
// Top-level single-line comment

/*
  Top-level multi-line comment
*/

type Example {
  // Inside block
  field string
}

7. Docstrings

  • Place docstrings immediately above the element they document.
  • Enclose in triple quotes ("""), preserving internal newlines and formatting.
  • Prefer concise, purpose-first text.
  • Use a blank line after a standalone docstring node.
"""
Represents a user in the system.
"""
type User {
  """ The unique identifier. """
  id string

  """ The user's full name. """
  name string
}

8. Naming Conventions

The formatter automatically enforces the following naming conventions:

ElementConventionExample
Types and EnumsPascalCaseUserProfile, OrderStatus
Enum MembersPascalCasePending, InProgress
Type MemberscamelCaseuserId, createdAt
ConstantscamelCasemaxPageSize, apiVersion
AnnotationscamelCaserpc, proc, deprecated

Acronym Handling

Acronyms longer than two letters are treated as regular words:

// Correct
type HttpRequest { ... }
type JsonParser { ... }

// Incorrect
type HTTPRequest { ... }
type JSONParser { ... }