stencil

Generate idiomatic types from JSON samples.
JSON Sample(s) → Inferrer → Intermediate Schema → Language Generator → Code
Supports TypeScript, Go, Python, Java, and C#. The intermediate schema is language-agnostic so more targets stay easy to add.
Install
go install github.com/justinwilliams-io/stencil/cmd/stencil@latest
Or build from source:
git clone https://github.com/justinwilliams-io/stencil.git
cd stencil
go build -o stencil ./cmd/stencil
Usage
Interactive (default in a terminal)
Pass the sample JSON path. stencil infers the shape, asks for a type name, prints the code, then asks whether to write a file.
stencil testdata/user.json
Inferred shape:
User
email: string
id: int
name: string
profile: Profile
tags: array<string>
Profile
active: bool
bio: string
Type name [User]:
# ... generated code on stdout ...
Write to a file? [Y/n]:
Output path [User.ts]:
Language defaults to TypeScript. Override with -l if you already know:
stencil -l py testdata/user.json
stencil -l go,cs --package models testdata/user.json
Use -y / --yes to skip prompts (CI/scripts).
Scripting
# version
stencil version
stencil -v
# stdin → stdout (no TTY → no prompts)
echo '{"id":1,"name":"a"}' | stencil --stdin -n User
# Go structs
echo '{"id":1,"name":"a"}' | stencil --stdin -l go -n User --package models
# Python dataclasses
echo '{"id":1,"name":"a"}' | stencil --stdin -l py -n User
# Java (Jackson annotations)
echo '{"id":1,"name":"a"}' | stencil --stdin -l java -n User --package com.example.models
# C# (System.Text.Json)
echo '{"id":1,"name":"a"}' | stencil --stdin -l cs -n User --package MyApp.Models
# files (merged as samples), non-interactive
stencil -y -n User testdata/user.json testdata/user_partial.json
# several languages into a directory
stencil -y -n User -l ts,go,py,java,cs -o ./gen --package models testdata/user.json
# array of objects = multiple samples
stencil -y -n Item testdata/mixed_types.json
Flags
| Flag |
Default |
Description |
-l, --lang |
ts |
Target languages (comma-separated): ts, go, py, java, cs |
-n, --name |
(filename or prompt) |
Root type name |
-o, --out |
(stdout or prompt) |
Output file or directory |
--stdin |
false |
Read JSON from stdin |
--nullable |
union |
union | optional | strict |
--package |
language default |
Go package, Java package, or C# namespace |
--just-types |
true |
Types only (no serializers) |
-y, --yes |
false |
Non-interactive; never prompt |
-v, --version |
|
Print version |
Language aliases: typescript→ts, golang→go, python→py, csharp/c#→cs.
Null handling (--nullable)
| Mode |
Behavior |
union |
JSON null becomes T | null (TS), *T (Go), Optional[T] (Python), nullable refs (Java/C#); missing keys become optional |
optional |
null and missing both become optional (null stripped where possible) |
strict |
null always stays visible in the type; missing → optional |
Examples
TypeScript
stencil -n User testdata/user.json testdata/user_partial.json
// Code generated by stencil. DO NOT EDIT.
export interface Profile {
active: boolean;
bio: string;
}
export interface User {
email?: string;
id: number;
name: string;
profile: Profile;
tags?: string[];
}
Go
stencil -l go -n User --package models testdata/user.json testdata/user_partial.json
// Code generated by stencil. DO NOT EDIT.
package models
type Profile struct {
Active bool `json:"active"`
Bio string `json:"bio"`
}
type User struct {
Email *string `json:"email,omitempty"`
ID int64 `json:"id"`
Name string `json:"name"`
Profile Profile `json:"profile"`
Tags []string `json:"tags,omitempty"`
}
Python
stencil -l py -n User testdata/user.json testdata/user_partial.json
# Code generated by stencil. DO NOT EDIT.
from __future__ import annotations
from dataclasses import dataclass
from typing import Any, Optional, Union
@dataclass
class Profile:
bio: str
active: bool
@dataclass
class User:
id: int
name: str
profile: Profile
email: Optional[str] = None
tags: Optional[list[str]] = None
Java
stencil -l java -n User --package com.example.models testdata/user.json
Generates Jackson-annotated POJOs (@JsonProperty, getters/setters). Default package: types.
C#
stencil -l cs -n User --package MyApp.Models testdata/user.json
Generates sealed classes with System.Text.Json [JsonPropertyName]. Default namespace: Types.
Library layout
cmd/stencil/ CLI entrypoint
internal/cli/ Cobra commands + interactive prompts
internal/infer/ JSON → intermediate schema (+ merge)
internal/schema/ IR types
internal/generate/typescript TypeScript generator
internal/generate/golang Go generator
internal/generate/python Python generator
internal/generate/java Java generator
internal/generate/csharp C# generator
internal/version/ Version metadata
License
MIT