Skip to content

Go-First Workflow

This guide explains the Go-first approach to JSON Schema and documentation, where Go structs are the single source of truth.

Philosophy

Traditional schema-first development requires maintaining schemas and code in sync. The Go-first approach inverts this:

                    ┌─────────────────┐
                    │   Go Structs    │
                    │ (Source of      │
                    │     Truth)      │
                    └────────┬────────┘
                             │
              ┌──────────────┼──────────────┐
              │              │              │
              ▼              ▼              ▼
        ┌───────────┐  ┌───────────┐  ┌───────────┐
        │   JSON    │  │  Markdown │  │    Go     │
        │  Schema   │  │   Spec    │  │ Validation│
        └───────────┘  └───────────┘  └───────────┘

Benefits

  • Single source of truth - No schema/code drift
  • Type safety - Go compiler catches errors
  • Doc comments - Documentation lives with code
  • IDE support - Full autocomplete and refactoring

Complete Workflow

1. Define Types in Go

// Package config defines application configuration types.
package config

// Config is the root configuration type.
type Config struct {
    // App contains application settings.
    App AppConfig `json:"app"`

    // Database contains database connection settings.
    Database DatabaseConfig `json:"database,omitempty"`
}

// AppConfig contains application-level settings.
type AppConfig struct {
    // Name is the application name.
    Name string `json:"name"`

    // Environment is the deployment environment.
    Environment Environment `json:"environment"`

    // Debug enables debug mode.
    Debug bool `json:"debug,omitempty"`
}

// Environment represents deployment environments.
type Environment string

const (
    // EnvironmentDev is the development environment.
    EnvironmentDev Environment = "dev"

    // EnvironmentStaging is the staging environment.
    EnvironmentStaging Environment = "staging"

    // EnvironmentProd is the production environment.
    EnvironmentProd Environment = "prod"
)

2. Generate JSON Schema

schemakit generate github.com/myorg/myproject/config Config \
  -o schema/config.schema.json

3. Generate Documentation

schemakit doc github.com/myorg/myproject/config Config \
  -t "Configuration Specification" -v v1.0.0 \
  -o docs/config-spec.md

4. Validate Schema (Optional)

schemakit lint schema/config.schema.json

Project Structure

myproject/
├── config/
│   ├── config.go         # Go types (source of truth)
│   └── config_test.go    # Tests
├── schema/
│   └── config.schema.json  # Generated
├── docs/
│   ├── header.md           # Human-authored
│   └── config-spec.md      # Generated (with header)
└── Makefile

Makefile Integration

VERSION ?= v1.0.0

.PHONY: schema docs lint

schema:
    schemakit generate github.com/myorg/myproject/config Config \
      -o schema/config.schema.json

docs:
    schemakit doc --prepend docs/header.md \
      -t "Configuration Specification" -v $(VERSION) \
      github.com/myorg/myproject/config Config \
      -o docs/config-spec.md

lint:
    schemakit lint schema/config.schema.json

all: schema docs lint

CI Integration

# .github/workflows/schema.yml
name: Schema
on: [push, pull_request]

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: '1.24'

      - name: Install schemakit
        run: go install github.com/grokify/schemakit/cmd/schemakit@latest

      - name: Generate schema
        run: make schema

      - name: Lint schema
        run: make lint

      - name: Check for changes
        run: |
          git diff --exit-code schema/
          if [ $? -ne 0 ]; then
            echo "Schema is out of date. Run 'make schema' and commit."
            exit 1
          fi

Embedding Schemas

Use Go's embed directive for runtime access:

package schema

import _ "embed"

//go:embed config.schema.json
var ConfigSchema []byte

//go:embed config.schema.json
var ConfigSchemaString string

Version Control

Commit both source and generated files:

git add config/config.go
git add schema/config.schema.json
git add docs/config-spec.md
git commit -m "feat: add configuration types with schema and docs"

This ensures the repository always has up-to-date artifacts.