Skip to content

Data Model

Norn persists all state in PostgreSQL using pgx. The schema is auto-migrated on startup.

Entity relationship diagram

Tables

deployments

Tracks every deploy attempt with full step-by-step logs.

ColumnTypeDescription
idTEXT PKUUID
appTEXTApp identifier
commit_shaTEXTGit commit SHA
image_tagTEXTDocker image tag (e.g. myapp:abc123def456)
statusTEXTOne of: queued, building, testing, snapshotting, migrating, deploying, deployed, failed, rolled_back
stepsJSONBArray of step logs with name, status, duration, output
errorTEXTError message if failed
started_atTIMESTAMPTZWhen the deploy was queued
finished_atTIMESTAMPTZWhen the deploy completed or failed

Indexes: idx_deployments_app, idx_deployments_status

forge_states

One row per app, tracking infrastructure provisioning state.

ColumnTypeDescription
appTEXT PKApp identifier
statusTEXTOne of: unforged, forging, forged, forge_failed, tearing_down
stepsJSONBArray of forge step logs
resourcesJSONBCreated resources (deployment name, service name, hosts, DNS/tunnel flags)
errorTEXTError message if failed
started_atTIMESTAMPTZWhen the operation started
finished_atTIMESTAMPTZWhen the operation completed

health_checks

Health check results from periodic polling.

ColumnTypeDescription
idTEXT PKUUID
appTEXTApp identifier
healthyBOOLEANWhether the check passed
response_msINTEGERResponse time in milliseconds
checked_atTIMESTAMPTZWhen the check ran

Index: idx_health_checks_app_time (app, checked_at DESC)

Pruned automatically — records older than 24 hours are deleted.

cron_executions

Tracks every cron job execution.

ColumnTypeDescription
idBIGSERIAL PKAuto-increment
appTEXTApp identifier
image_tagTEXTDocker image used
statusTEXTrunning, completed, failed
exit_codeINTContainer exit code
outputTEXTContainer stdout/stderr
duration_msBIGINTExecution duration
started_atTIMESTAMPTZWhen execution started
finished_atTIMESTAMPTZWhen execution completed

func_executions

Tracks every function invocation.

ColumnTypeDescription
idBIGSERIAL PKAuto-increment
appTEXTApp identifier
image_tagTEXTDocker image used
statusTEXTrunning, succeeded, failed, timed_out
exit_codeINTContainer exit code
outputTEXTContainer stdout/stderr
duration_msBIGINTExecution duration
started_atTIMESTAMPTZWhen execution started
finished_atTIMESTAMPTZWhen execution completed

cron_states

One row per cron app, tracking schedule and pause state.

ColumnTypeDescription
appTEXT PKApp identifier
scheduleTEXTCron expression
pausedBOOLEANWhether scheduling is paused
next_run_atTIMESTAMPTZNext scheduled execution
updated_atTIMESTAMPTZLast state change

cluster_nodes

Tracks provisioned cluster nodes across cloud providers.

ColumnTypeDescription
idTEXT PKUUID
nameTEXTNode name (e.g. norn-server-1)
providerTEXTCloud provider (hetzner, digitalocean, vultr)
regionTEXTRegion code
sizeTEXTInstance size
roleTEXTserver or agent
public_ipTEXTPublic IP address
tailscale_ipTEXTTailscale mesh IP
statusTEXTprovisioning, ready, draining, removed
provider_idTEXTCloud provider resource ID
errorTEXTError message
created_atTIMESTAMPTZWhen the node was created
updated_atTIMESTAMPTZLast status change

Step log format

Both deploy and forge pipelines store step logs as JSONB arrays:

json
[
  {
    "step": "clone",
    "status": "deployed",
    "durationMs": 1234,
    "output": "cloned git@github.com:user/app.git (branch main) at abc123def456"
  },
  {
    "step": "build",
    "status": "deployed",
    "durationMs": 45678,
    "output": "..."
  }
]

Crash recovery

On startup, Norn marks all in-flight operations as failed:

  • Deployments: Any deployment not in deployed, failed, or rolled_back status is marked failed with error "norn restarted during deployment"
  • Forge states: Any forge in forging or tearing_down status is marked forge_failed with error "norn restarted during operation"

This ensures no operations are ever left in an indeterminate state.