Putnami
DocsGitHub

Licensed under FSL-1.1-MIT

Getting Started
Concepts
How To
Build A Web App
Build An Api Service
Share Code Between Projects
Configure Your App
Add Persistence
Add Authentication
Add Background Jobs
Develop With Ai
Structure Business Logic With Di
Upgrade Putnami
Principles
Tooling & Workspace
Workspace
Cli
Jobs & Caching
Extensions
Templates
Error Handling
Frameworks
Typescript
ExtensionOverviewWebReact RoutingForms And ActionsStatic FilesApiErrors And ResponsesConfigurationLoggingHttp And MiddlewareDependency InjectionPlugins And LifecycleSessionsAuthPersistenceEventsStorageCachingWebsocketsTestingHealth ChecksTelemetryProto GrpcSmart ClientSchema
Go
ExtensionOverviewHttpDependency InjectionPlugins And LifecycleConfigurationSecurityPersistenceErrorsEventsStorageCachingLoggingTelemetryGrpcService ClientsValidationOpenapiTesting
Python
Extension
Platform
Ci
  1. DocsSeparator
  2. FrameworksSeparator
  3. TypescriptSeparator
  4. Extension

TypeScript Extension

The @putnami/typescript extension provides the standard TypeScript toolchain for Putnami workspaces. It handles building, testing, linting, serving, and publishing for JS/TS projects using Bun and Biome.

Scope: All jobs are project-only — they require a project context.

External tools

  • Bun
  • Biome

Enable the extension

putnami deps add @putnami/typescript

The extension is auto-discovered from workspace dependencies.

Jobs

generate

Run code generation hooks before building. Automatically invoked by build and test, but can be run standalone.

Key steps:

  • Discover pre-build hooks from plugin dependencies
  • Execute hooks in dependency order
  • Output generated exports and assets to .gen/

Options:

  • --verbose — Show detailed generation output
  • --clear — Clear existing generated artifacts before generating
putnami generate .
putnami generate . --clear

build

Compile TypeScript packages for distribution using Bun's bundler.

Pipeline phases:

  • generate — pre-build hooks + generated artifacts
  • transpile — JS package output (output/lib)
  • types — declaration output (output/types)
  • compile — standalone binary output (output/compile)

Default behavior: if no phase flags are provided, build runs generate + transpile + types. The compile phase is opt-in via --compile. If any phase flag is provided, only selected phases run.

Options:

  • Phase control: --generate, --transpile, --types, --compile
  • --target <bun|browser|node> (default: bun)
  • --compile-target <bun-*> (single executable target, e.g., bun-linux-x64)
  • --bundle <standalone|local|none> (default: none)
  • --sourcemap <inline|external|none> (default: external)
  • --minify <boolean> (default: true)
  • --splitting — Enable code splitting (ESM format required)
  • --assets <path> (multiple allowed)
  • --publish-config-access <public|restricted> (default: public)
  • --version-suffix <suffix> (overrides git-derived suffix)
  • --release — Build for stable release (skips version suffix)
  • --fast — Skip type generation
  • --skip-package-json, --skip-artifacts
  • --clear — Wipe output folder first

Compile targets: default targets when --compile is enabled:

  • bun-linux-x64, bun-linux-arm64
  • bun-darwin-x64, bun-darwin-arm64

Executable outputs are discovered from build.compile in .putnamirc.json or bin entries in package metadata.

Version and metadata: the build automatically reads the workspace version and adds a suffix for pre-release builds ({baseVersion}-{hash}, e.g., 1.0.0-a1b2c3d). The suffix is a 7-character hash of source files, ensuring deterministic versions.

putnami build . --target bun
putnami build . --compile
putnami build . --compile --compile-target bun-linux-x64

test

Run tests using Bun's test runner.

  • Discovers tests with **/*.{test,spec}.{ts,tsx,js,jsx}
  • If no tests are found, returns SKIP
  • Produces JUnit output and optional LCOV coverage

Options:

  • --timeout <ms> (default: 5000)
  • --coverage
  • --test-name-pattern <regex>
  • --test <filter> / -t
  • --only, --todo, --bail <n>, --concurrent <n>
  • --update-snapshots
  • --pass-with-no-tests <boolean> (default: true)
putnami test . --coverage

lint

Format and lint using Biome.

  • Runs biome format then biome lint
  • Config resolution: project biome.json → workspace root biome.json → built-in config

Options:

  • --config-path <path> (default: node_modules/@putnami/typescript/config)
  • --fix <boolean> (default: true)
  • --max-diagnostics <number> (default: 10)
  • --diagnostic-level <error|warn|info|off> (default: warn)
putnami lint . --fix

serve

Start a dev server with hot reload.

  • Resolves ./serve export from package.json or uses --entrypoint
  • If ./serve is missing, runs putnami build <project> --fast first

Options:

  • --entrypoint <path>
  • --watch <boolean> (default: true)
  • --port <number> (default: 3000)
  • --debug — Forward LOG_LEVEL=debug to the application
  • --no-services — Disable multi-service discovery
  • --inspect, --inspect-wait, --inspect-brk
putnami serve . --port 4000

Multi-service mode: declare runtime service dependencies in package.json:

{
  "putnami": {
    "runsWith": ["catalogue-api", "profile-api"]
  }
}

Running putnami serve web-app --watch auto-discovers, allocates ports, and starts all declared services. If runsWith is not declared, the system walks the dependency graph for projects with ./serve exports.

Port conflict resolution: the system checks for port conflicts before starting. Conflicts are resolved interactively (or automatically in CI), and the chosen port is saved to the project config for future runs.

publish

Provided by the @putnami/ci extension. Documented here because it handles TypeScript-specific publishing behavior.

Publish built packages, optional binary assets, and optional extension archives.

Subtasks (enabled by project publish channels):

  • npm — publish package(s) and manage dist-tags
  • assets — upload compiled binaries to GCS
  • archives — upload extension .tar.gz archives to GCS

Options:

  • --stable — Publish stable version (strips suffix, tags as latest)
  • --dist-tag <tag> — Override npm dist-tag
  • --also-branch-tag — Also publish branch-derived tag manifest
  • --access <public|restricted> (default: public)
  • --otp <code>
  • --registry <url> — Custom npm registry
  • --assets-bucket <bucket>, --assets-prefix <prefix> — GCS config for binaries
  • --archives-bucket <bucket>, --archives-prefix <prefix> — GCS config for archives
  • --dry-run

Enable channels in project config:

{
  "publish": ["npm", "assets", "archives"]
}
# Pre-release
putnami build .
putnami publish .

# Stable
putnami build .
putnami publish . --stable

Docker

When the docker publish channel is enabled, the TypeScript extension generates a Dockerfile using oven/bun:slim as the base image and copies the pre-compiled standalone bundle into the container.

Enable in project config:

{
  "publish": ["npm", "docker"]
}

Options: --docker-registry <registry>, --docker-tag <tag>, --platform <platform> (default: linux/amd64), --port <number> (default: 3000), --stable.

putnami publish my-app --docker-registry ghcr.io/myorg

Caching and dependencies

  • generate depends on ^generate, cached with: src/**/*.ts, src/**/*.tsx, package.json. Quiet job (hidden from recap on success).
  • build depends on generate and ^build, cached with: src/**/*.ts, src/**/*.tsx, tsconfig.json, tsconfig.app.json, tsconfig.lib.json, package.json, doc/**/*.
  • test depends on generate, cached with: src/**/*.ts, src/**/*.tsx, test/**/*.ts, test/**/*.tsx, package.json.
  • lint cached with: src/**/*.ts, src/**/*.tsx, biome.json, package.json.
  • serve depends on build --fast, never cached.
  • publish depends on build --transpile --types and ^publish.

Pre-build hooks

Dependencies can contribute pre-build hooks to generate sources or assets before compilation. Hooks are discovered from plugin packages via the pre-build export.

Hook CLI arguments: the runner passes --context <path> and --result <path>. Write the JSON result to --result:

{
  "exports": {
    "./generated": "./.gen/main.ts"
  },
  "assets": [
    { "src": ".gen/schema.json", "dest": "schema.json" }
  ]
}

Create a hook

  1. Create src/pre-build/index.ts exporting preBuild with command and optional args
  2. Create the command script that writes JSON to --result
  3. Add an export in package.json:
{
  "exports": {
    "./pre-build": "./src/pre-build/index.ts"
  }
}

Project templates

Template Description
typescript-web React SSR web app with file-based routing, layouts, and client hydration
typescript-server HTTP server with @putnami/application, file-based API routing, and tests
typescript-library TypeScript library with exports and tests
putnami projects create my-app --template typescript-web
putnami projects create my-api --template typescript-server
putnami projects create my-lib --template typescript-library

Every template produces a project you can serve or test immediately.

On this page

  • TypeScript Extension
  • External tools
  • Enable the extension
  • Jobs
  • generate
  • build
  • test
  • lint
  • serve
  • publish
  • Docker
  • Caching and dependencies
  • Pre-build hooks
  • Create a hook
  • Project templates