npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

trident-template

v2.0.7

Published

A **multiplicative templating engine** that eliminates configuration sprawl.

Readme

Trident

A multiplicative templating engine that eliminates configuration sprawl.

The Problem

You have 10 microservices. Each needs a deployment file, a service file, and a config file. That's 30 files to maintain—mostly identical, with small differences like service name, port, and replica count.

Now you need to add a label to every deployment. Or change a resource limit. Or add an 11th service. Every change means touching multiple files. Copy, paste, find, replace, hope you didn't miss one.

The Solution

Trident flips the problem. Instead of maintaining 30 files, you maintain:

  • 1 manifest listing your 10 services and their properties
  • 1 template defining the 3 file types each service needs

Trident multiplies them: 10 services × 3 templates = 30 files

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  Manifest   │     │  Template   │     │   Output    │
│             │  ×  │             │  =  │             │
│ 10 services │     │ 3 documents │     │  30 files   │
└─────────────┘     └─────────────┘     └─────────────┘

Add a service? Add one manifest entry. Change a pattern? Edit one template. Consistency is guaranteed.

Quick Example

manifest.yaml — your data:

name: api
port: 8080
replicas: 3
---
name: web
port: 3000
replicas: 2
---
name: worker
replicas: 5

template.yaml — what to generate:

# $out specifies where to write the file
$out: {{name}}/deployment.yaml
kind: Deployment
metadata:
  name: {{name}}
spec:
  replicas: {{replicas}}
---
$out: {{name}}/service.yaml
kind: Service
metadata:
  name: {{name}}-svc
spec:
  ports:
    - port: {{port}}

Run it:

trident -i .

Result: 6 files generated

api/deployment.yaml    web/deployment.yaml    worker/deployment.yaml
api/service.yaml       web/service.yaml       worker/service.yaml

Installation

npm install -g trident-template

Core Concepts

Manifests

A manifest is a multi-document YAML file. Each --- separator creates a new item:

name: api
port: 8080
---
name: web
port: 3000

Items can have any structure. By default, each needs a name field.

Templates

Templates define output files using $out. Each document produces one file per manifest item:

$out: {{name}}/config.yaml
service: {{name}}
port: {{port}}

Handlebars syntax ({{...}}) interpolates manifest values. Objects and arrays are automatically serialized to JSON.

Base Files and Deep Merge

Use $in to start with a base file and layer your template on top:

$in: base/deployment.yaml
$out: {{name}}/deployment.yaml
metadata:
  name: {{name}}
spec:
  replicas: {{replicas}}

Trident deep merges the base with your template:

  • Objects merge recursively—keys from both sides are preserved
  • Template values override base values when they conflict
  • Arrays are replaced, not merged

$in also accepts an array of files, merged in order:

$in:
  - base/deployment.yaml
  - overrides/{{environment}}.yaml
$out: {{name}}/deployment.yaml

Schema Validation

Validate manifest items and apply defaults with JSON Schema:

$template: deploy.yaml
$manifest: services.yaml
$schema: schema.json
{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "replicas": { "type": "integer", "default": 1, "minimum": 1 }
  },
  "required": ["name"]
}

Nested Templates

Templates can invoke other templates. This is useful for:

Project organization — A root template orchestrates sub-templates with their manifests:

$template: backend/template.yaml
$manifest:
  - backend/manifest.yaml
  - backend/{{$values.env}}-overrides.yaml
---
$template: frontend/template.yaml
$manifest: frontend/manifest.yaml

Multiplicative composition — Outer and inner templates multiply together:

$template: services/template.yaml
$manifest: services/manifest.yaml
environment: {{name}}

2 environments × 3 services × 2 files = 12 output files.

Multiple Manifests

Merge manifests by name for environment-specific overrides:

$template: deploy.yaml
$manifest:
  - base.yaml
  - prod-overrides.yaml

Items with the same name are deep merged. Later files override earlier ones.

Global Values

Pass values via CLI:

trident -i . -v environment=prod -f config=prod.json

Access via $values:

$out: {{name}}/config.yaml
environment: {{$values.environment}}
database: {{$values.config.database}}

Directives Reference

| Directive | Purpose | Example | |-----------|---------|---------| | $out | Output file path | $out: {{name}}/config.yaml | | $in | Base file(s) to merge | $in: base.yaml or $in: [base.yaml, override.yaml] | | $text | Raw text output | $text: "server { listen {{port}}; }" | | $root | Preserve $-prefixed keys in output | $root: { $schema: "..." } | | $copy | Copy files | $copy: assets/*.txt | | $merge | Merge multiple files | $merge: { files: ["*.yaml"], separator: "---\n" } | | $replace | String replacement | $replace: { __NAME__: "{{name}}" } | | $template | Invoke another template | $template: inner/template.yaml | | $manifest | Specify manifest(s) | $manifest: [base.yaml, overrides.yaml] | | $schema | JSON Schema for validation | $schema: schema.json | | $values | Import values | $values: [{ config: config.json }] | | $chdir | Change output directory | $chdir: output/{{name}} | | $mkdir | Create directories | $mkdir: output/{{name}} | | $rm | Remove files/directories | $rm: temp/*.yaml | | $exec | Run shell command (requires --enable-exec) | $exec: echo "Done" |

Helpers

Trident includes custom helpers:

# Data
{{default port 8080}}              # Fallback value
{{or customPort defaultPort 8080}} # First truthy value
{{merge defaults overrides}}       # Deep merge objects
{{object "key" value}}             # Construct object

# Numeric
{{min replicas 10}}                # At most 10
{{max replicas 1}}                 # At least 1
{{clamp replicas 1 10}}            # Between 1 and 10

# Files
{{read "config.txt"}}              # Read file contents
{{hash "config.json"}}             # SHA256 hash
{{ls "configs/*.yaml"}}            # List files
{{read_glob "*.yaml" true}}        # Read and parse multiple files

# Comparison
{{#if (eq a b)}}...{{/if}}
{{#if (gt replicas 1)}}...{{/if}}
{{#if (and condition1 condition2)}}...{{/if}}

CLI Reference

trident -i .                        # Process current directory
trident -i . --dry                  # Preview without writing
trident -i services -i frontend     # Multiple inputs
trident -i . -v env=prod            # Pass values
trident -i . -f config=prod.json    # Import values from file
trident -i . --enable-exec          # Allow $exec directive

| Flag | Description | |------|-------------| | -i, --input | Input directory or files | | --dry | Preview output without writing | | -v | Set value (e.g., -v key=value) | | -f | Import values from file (e.g., -f config=file.json) | | --enable-exec | Allow $exec directive (disabled by default) |

Output Formats

Output format is determined by $out file extension:

| Extension | Format | |-----------|--------| | .yaml, .yml | YAML | | .json | JSON | | .xml | XML | | Other | YAML (default) |

For non-structured output, use $text:

$out: {{name}}/nginx.conf
$text: |
  server {
      listen {{port}};
      server_name {{name}}.example.com;
  }

How It Compares

The biggest advantage of Trident is managing configuration sprawl. 10 services × 3 environments × 4 file types = 120 files to maintain. With Trident, you maintain manifests (your data) and templates (your patterns)—not hundreds of repetitive files.

This makes GitOps workflows cleaner:

  • PRs show changes to services and their properties, not 50 similar files
  • Adding a service means adding manifest entries, not copy-pasting files
  • Environment overrides live in dedicated files, merged automatically

| Feature | Trident | Helm | Kustomize | |---------|---------|------|-----------| | Templating | Yes | Yes | No | | Patching/Overlays | Yes | No | Yes | | Multiplicative | Yes | No | No | | Kubernetes-specific | No | Yes | Yes |

vs Helm: No explicit loops needed—manifest items multiply automatically. Supports patching, which Helm doesn't.

vs Kustomize: Adds templating on top of patching. Variables, conditionals, and helpers—not just overlays.

vs Jsonnet: Stays in YAML. No new language to learn.

See the full comparison for detailed examples and migration guides.

Documentation

Why "Trident"?

A trident is a multi-pronged tool. Trident gives your configurations multiple prongs—one source, many outputs.