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
Principles
Tooling & Workspace
Workspace Overview
Cli
Jobs & Commands
SDK
Error Handling
Extensions
Typescript
Go
Python
Docker
Ci
Frameworks
Typescript
OverviewWebReact RoutingForms And ActionsStatic FilesApiErrors And ResponsesConfigurationLoggingHttp And MiddlewareDependency InjectionPlugins And LifecycleSessionsAuthPersistenceEventsStorageCachingWebsocketsTestingHealth ChecksTelemetryProto GrpcSmart Client
Go
OverviewHttpDependency InjectionPlugins And LifecycleConfigurationSecurityPersistenceErrorsEventsStorageCachingLoggingTelemetryGrpcService ClientsValidationOpenapiTesting
Platform
  1. DocsSeparator
  2. Tooling & WorkspaceSeparator
  3. Workspace Overview

Workspace overview

A workspace is the unit of organization in Putnami. It is a single folder identified by a .putnamirc.json file at the root that defines how projects are discovered, how commands run, and how dependencies are resolved across the repo.

Key ideas

  • apps/ typically contains deployable applications (convention, not enforced)
  • packages/ typically contains shared code (convention, not enforced)
  • A .putnamirc.json file at the root identifies the workspace

What a project can be

Putnami treats each project as a distinct unit with its own build/test/deploy jobs. Each project has a canonical ID computed as "/" + path (e.g. /typescript/frameworks/web). This ID is used in CLI output, dependency declarations, and target expressions.

Common shapes include:

  • App — a runnable/deployable project (web, API, worker)
  • Library — shared code used by other projects
  • Runtime — a host for running jobs (e.g., typescript, python, go...)

Typical structure

my-workspace/ apps/ web/ package.json packages/ shared/ package.json .putnamirc.json # workspace configuration package.json # root package.json

Organization patterns (examples)

# flat
<project-a>
<project-b>

# Classic apps + packages
apps/<project>
packages/<project-a>
packages/<project-b>

# Domain-based
domains/<domain>/services/<project>
domains/<domain>/jobs/<project>
domains/<domain>/libs/<project>

# Language-first with scopes
go/framework/<project>
go/samples/<project>
typescript/framework/<project>
typescript/samples/<project>

Scopes

Scopes are an organizational layer between the workspace and projects. A scope is a directory with a .putnamirc.json that declares its own projects, tags, extensions, and groups. This decentralizes project ownership — each subtree manages its own config instead of everything living in the root.

Defining scopes

Register scope directories in the root .putnamirc.json:

{
  "scopes": ["go/framework", "typescript/framework", "typescript/samples"],
  "projects": ["tooling/cli", "platform/ci"]
}

Each scope directory has its own .putnamirc.json with scope-specific configuration:

{
  "projects": ["app", "http", "sql", "inject"],
  "tags": ["go"],
  "extensions": ["@putnami/go"],
  "publishConfig": {
    "go": { "namePattern": "go.putnami.dev/{name}" }
  },
  "groups": {
    "go-core": "/go/framework/app,/go/framework/inject"
  }
}

Scope inheritance

Scopes form an inheritance chain from the workspace root down to each project:

  • Tags: merged (union) — a project inherits all tags from its ancestor scopes
  • Extensions: deepest scope wins (replaces parent)
  • PublishConfig: deepest scope wins per channel
  • Groups and aliases: aggregated across all scopes (duplicates are errors)

When to use scopes

Scopes are most useful when your workspace has many projects organized by language or domain. Instead of listing 50+ projects in the root config, you declare 5 scopes that each manage their own subtree:

  • go/framework/ — 16 Go framework modules
  • typescript/framework/ — 9 TypeScript packages
  • typescript/samples/ — 13 sample applications

Use putnami scopes list to see all scopes and their metadata.

Why it matters

  • Shared tooling: one lint/test/build workflow
  • Shared code: internal libraries are first-class
  • Clear boundaries: apps deploy, libraries share

How it works

  • Putnami discovers projects from workspace config and package metadata.
  • The CLI plans jobs across projects and resolves dependencies automatically.
  • Workspace dependency resolution is maintained by Putnami, so jobs run in the right order even when projects depend on each other.

Project discovery (high level)

Putnami discovers projects from three sources, in priority order:

  1. Scope-declared projects — each scope's .putnamirc.json projects array (paths relative to the scope directory)
  2. Explicit project paths — the root .putnamirc.json projects array
  3. Package manager workspaces — the root package.json workspaces field

If a project appears in multiple sources, the first source wins. This means you can organize projects however you like, as long as they are included in workspace discovery.

See also: Concepts

Next steps

  • Next: CLI

On this page

  • Workspace overview
  • Key ideas
  • What a project can be
  • Typical structure
  • Organization patterns (examples)
  • Scopes
  • Defining scopes
  • Scope inheritance
  • When to use scopes
  • Why it matters
  • How it works
  • Project discovery (high level)
  • Next steps