NNO Docs
ArchitectureServices

NNO Stack Registry

Documentation for NNO Stack Registry

Date: 2026-03-30 Status: Detailed Design Parent: System Architecture — Section 3, Layer 0 (NNO Core) Service: services/stack-registry (renamed from services/marketplace)


Overview

The NNO Stack Registry is the authoritative source of versioned Stack template definitions for the NNO platform. NNO operators publish stack templates here; platform admins and the provisioning service consume them.

What the Stack Registry does:

  • Stores NNO-authored stack template definitions as versioned JSON
  • Provides a browsable catalogue for platform admins to discover available stacks
  • Serves specific stack versions to the provisioning service during stack activation

What the Stack Registry does NOT do:

  • No submission pipeline — only NNO operators can publish templates (no external submissions)
  • No bundle storage — all feature packages are NNO-built and already in the monorepo; stack definitions are JSON only
  • No review process — NNO operators publish directly without a review queue

Who uses it:

  • NNO operators — publish and manage stack templates via API
  • Platform admins — browse available templates from Zero UI
  • Provisioning service — fetches StackDefinition JSON at stack activation time

1. D1 Schema

The Stack Registry has its own D1 database, separate from the NNO Registry. The databases retain their legacy marketplace-db names: nno-k3m9p2xw7q-marketplace-db (prod) and nno-k3m9p2xw7q-marketplace-db-stg (stg) — see §6 for details.

-- One row per NNO-authored stack template
CREATE TABLE stack_templates (
  id           TEXT PRIMARY KEY,
  name         TEXT NOT NULL UNIQUE,   -- kebab-case slug, e.g. 'saas-starter'
  display_name TEXT NOT NULL,          -- e.g. 'SaaS Starter Stack'
  description  TEXT NOT NULL,
  icon         TEXT,                   -- Lucide icon name
  domain       TEXT,                   -- Business domain grouping, e.g. 'saas', 'analytics'
  latest_version TEXT,                 -- Semver of latest active version
  status       TEXT NOT NULL DEFAULT 'active',  -- 'active' | 'deprecated'
  created_at   INTEGER NOT NULL,
  updated_at   INTEGER NOT NULL
);

-- One row per published version of a stack template
CREATE TABLE stack_versions (
  id                TEXT PRIMARY KEY,
  template_id       TEXT NOT NULL REFERENCES stack_templates(id),
  version           TEXT NOT NULL,             -- semver
  stack_definition  TEXT NOT NULL,             -- JSON StackDefinition
  nno_sdk_version   TEXT NOT NULL,             -- minimum @neutrino-io/sdk version required
  status            TEXT NOT NULL DEFAULT 'active',  -- 'active' | 'deprecated'
  published_at      INTEGER NOT NULL,
  created_at        INTEGER NOT NULL,
  UNIQUE(template_id, version)
);

CREATE INDEX idx_stack_templates_status  ON stack_templates(status);
CREATE INDEX idx_stack_versions_template ON stack_versions(template_id);
CREATE INDEX idx_stack_versions_status   ON stack_versions(template_id, status);
-- Note: idx_stack_templates_name does NOT exist — name has a UNIQUE constraint which
-- implicitly covers point-lookup queries. No migration has created this index.

2. API Surface

All endpoints are served by the Stack Registry Worker via the NNO Gateway. Base path: /api/v1/stacks.

Authentication: Authorization: Bearer \{nno-session-token\} on all requests. NNO operator token required for write endpoints.

Operator auth (Phase 1): Write endpoints check the x-nno-role request header for "operator" or "owner". This header is expected to be injected by the gateway or IAM session layer. Phase 2 will move to the standard AUTH_API_KEY bearer token model consistent with other services.

Browse (Platform Admins)

GET  /api/v1/stacks                    List active stack templates
GET  /api/v1/stacks/:name              Template detail + latest version StackDefinition
GET  /api/v1/stacks/:name/versions     All published versions for a template
GET  /api/v1/stacks/:name/:version     Specific version StackDefinition (used by provisioning)

GET /api/v1/stacks response:

{
  "data": [
    {
      "id": "tpl_saas_starter",
      "name": "saas-starter",
      "displayName": "SaaS Starter Stack",
      "description": "Complete SaaS starter with billing, settings, and analytics.",
      "icon": "Layers",
      "domain": "saas",
      "latestVersion": "1.0.0",
      "status": "active",
      "createdAt": "2026-02-28T10:00:00Z"
    }
  ],
  "total": 1
}

GET /api/v1/stacks/:name/:version response (consumed by provisioning service):

{
  "id": "tpl_saas_starter",
  "name": "saas-starter",
  "version": "1.0.0",
  "stackDefinition": {
    "id": "saas-starter",
    "version": "1.0.0",
    "displayName": "SaaS Starter Stack",
    "description": "Complete SaaS starter with billing, settings, and analytics.",
    "icon": "Layers",
    "features": [
      { "featureId": "billing", "required": true },
      { "featureId": "settings", "required": true },
      { "featureId": "analytics", "required": false }
    ],
    "resources": {
      "sharedD1": true,
      "sharedKV": true,
      "minimumPlan": "growth"
    },
    "permissions": ["saas-starter:access"]
  },
  "nnoSdkVersion": "1.0.0",
  "publishedAt": "2026-02-28T10:00:00Z"
}

Manage (NNO Operators Only)

POST   /api/v1/stacks                  Create a new template
POST   /api/v1/stacks/:name/versions   Publish a new version
PATCH  /api/v1/stacks/:name            Update display_name, description, icon, status
DELETE /api/v1/stacks/:name/:version   Deprecate a specific version

POST /api/v1/stacks request:

{
  "name": "saas-starter",
  "displayName": "SaaS Starter Stack",
  "description": "Complete SaaS starter with billing, settings, and analytics.",
  "icon": "Layers",
  "domain": "saas"
}

POST /api/v1/stacks/:name/versions request:

{
  "version": "1.0.0",
  "stackDefinition": { ... },   // Full StackDefinition object
  "nnoSdkVersion": "1.0.0"
}

3. Versioning Policy

Semver Rules

BumpAllowed changes
Patch (1.0.x)Bug fixes, description/icon updates, optional feature list changes
Minor (1.x.0)New optional features added, new optional resource requirements
Major (x.0.0)Required features added/removed, resource requirements changed, id renamed

Major version bumps indicate breaking changes that require platform admins to explicitly choose to upgrade.

Deprecation

Deprecated templates remain activatable — platforms that already have the template active are unaffected. Deprecated versions show a warning badge in Zero UI to encourage migration.

NNO operators mark a version or entire template as deprecated via PATCH /api/v1/stacks/:name (set status: 'deprecated').

latest_version Tracking

When a new version is published, the Stack Registry automatically updates stack_templates.latest_version to the highest semver among active versions. GET /api/v1/stacks/:name always returns the latest_version StackDefinition.


4. Integration with Provisioning Service

When a PROVISION_STACK job runs (see provisioning.md §2.3), step 1 fetches the StackDefinition:

PROVISION_STACK step 1: resolve_stack_definition
  → For registry template:
      GET /api/v1/stacks/{name}/{version} from stack-registry
      Validates all featureIds exist in the NNO feature catalogue
  → For local stack (is_local: true):
      StackDefinition is inline in the job payload
      Stack Registry is not called

The provisioning service uses the StackDefinition.features[] array to determine which features to activate and StackDefinition.resources to determine what CF primitives to create.


5. Built-in Stack Templates

NNO ships with the following first-party stack templates:

NameFeaturesResourcesMin Plan
saas-starterbilling, settings, analytics (optional)sharedD1, sharedKVgrowth
analytics-proanalytics, data-export, dashboards (optional)sharedD1, sharedR2, sharedKVgrowth
operator-suitezerosharedD1starter

These are published to the Stack Registry by NNO operators and are available to all platforms on the appropriate tier.


6. Wrangler Configuration

# services/stack-registry/wrangler.toml

# Default (no --env flag) = production
name = "nno-k3m9p2xw7q-stack-registry"
main = "src/index.ts"
compatibility_date = "2024-09-13"
compatibility_flags = ["nodejs_compat"]

# PRODUCTION (default)
[[d1_databases]]
binding       = "DB"
database_name = "nno-k3m9p2xw7q-marketplace-db"
database_id   = "33a6d03d-c191-4c18-a53d-5888be08ac73"
migrations_dir = "migrations"

[vars]
SERVICE_NAME = "stack-registry"
ENVIRONMENT  = "prod"

[[routes]]
pattern       = "stack-registry.svc.nno.app"
custom_domain = true

# STG ENVIRONMENT
[env.stg]
name = "nno-k3m9p2xw7q-stack-registry-stg"
[[env.stg.d1_databases]]
binding       = "DB"
database_name = "nno-k3m9p2xw7q-marketplace-db-stg"
database_id   = "543fa5be-bf3e-4917-90b9-4c586d24147c"
migrations_dir = "migrations"

[env.stg.vars]
SERVICE_NAME = "stack-registry"
ENVIRONMENT  = "stg"

[[env.stg.routes]]
pattern       = "stack-registry.svc.stg.nno.app"
custom_domain = true

Legacy D1 database names: The D1 databases retain their original marketplace-db names from when this service was services/marketplace. The worker and worker name have been updated to stack-registry, but the underlying D1 database resources have not been recreated — renaming a D1 database requires migrating data and updating the database_id. The legacy names are the source of truth; do not use stack-registry-db names.

No local / dev environments: Unlike some other NNO services, stack-registry only defines the default (prod) environment and env.stg. There is no wrangler-managed local or dev environment.

No NNO_METRICS binding: stack-registry does not have a metrics instrumentation binding (no NNO_METRICS KV or Analytics Engine binding in wrangler.toml). Unlike gateway or IAM, metrics are not wired in this service.

Note: R2 binding has been removed. Stack definitions are JSON stored in D1 — no bundle storage required.

Secrets

SecretDescription
AUTH_API_KEYShared secret for service-to-service authentication
CORS_ORIGINSComma-separated allowed origins
NNO_REGISTRY_URLRegistry Worker URL
NNO_INTERNAL_API_KEYService-to-service auth with Registry

Status: Detailed design — Stack Registry replaces Marketplace 2026-02-28 Implementation target: services/stack-registry/ (renamed from services/marketplace/) Related: System Architecture · Stacks · Provisioning · Registry

On this page