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. Tooling & WorkspaceSeparator
  3. Workspace

Workspace

A workspace is the root of a Putnami project. It is a single directory identified by a putnami.workspace.json file that defines how projects are discovered, how dependencies are resolved, and how jobs run across the entire codebase.

Projects

Every project has a canonical ID computed as "/" + path relative to the workspace root (e.g., /typescript/frameworks/web). This ID is used in CLI output, dependency declarations, and target expressions.

Projects come in two shapes:

  • App — a runnable or deployable project (web app, API, worker)
  • Library — shared code consumed by other projects

Use putnami projects list to see all projects and their IDs.

Workspace structure

You can organize projects however you like. Common patterns:

# Classic apps + packages
apps/<project>
packages/<project>

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

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

A minimal workspace:

my-workspace/
  apps/
    web/
      package.json
  packages/
    shared/
      package.json
  putnami.workspace.json
  package.json

Project discovery

Putnami discovers projects from three sources, in priority order:

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

If a project appears in multiple sources, the first source wins.

Scopes

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

Register scope directories in putnami.workspace.json:

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

Each scope directory has its own putnami.json:

{
  "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)

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 a few scopes that each manage their own subtree.

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

Tags and filtering

Projects can declare tags in putnami.json or in package.json under the putnami key:

{
  "name": "@myorg/my-app",
  "tags": ["frontend", "deployable"]
}

Use tags to narrow which projects a job targets:

putnami build --all --tag frontend
putnami test --all --exclude-tag e2e
putnami build --all --tag backend,deployable

Tags listed in putnami.workspace.json under disable.tags are excluded from all selections by default. Use --tag to explicitly include them:

{
  "disable": {
    "tags": ["e2e"]
  }
}

Dependency graph and --impacted

Putnami maintains a dependency graph across all projects in the workspace. The --impacted flag uses this graph to run jobs only on projects affected by git changes compared to the main branch.

A project is impacted if:

  • It has changed files, or
  • It depends on a project with changed files

Impact propagates transitively — if a shared library changes, every project that depends on it (directly or indirectly) is considered impacted.

# Build only what changed
putnami build --impacted

# Preview what would run
putnami build --impacted --plan

On the main branch, --impacted falls back to --all.

Aliases and groups

Define shortcuts in putnami.workspace.json for frequently used targets:

{
  "projectAliases": {
    "web": "/typescript/frameworks/web",
    "cli": "/tooling/cli"
  },
  "groups": {
    "frontend": "/typescript/frameworks/web,/typescript/frameworks/ui",
    "all-go": "/go/..."
  }
}

Aliases and groups can also be defined in scope-level putnami.json files.

Introspection commands

putnami workspace describe          # Workspace name, root, version
putnami projects list               # All projects with paths and tags
putnami projects describe <project> # Dependencies, exports, config for one project
putnami scopes list                 # All scopes with project counts and tags

All introspection commands support --output=jsonl for machine-readable output.

On this page

  • Workspace
  • Projects
  • Workspace structure
  • Project discovery
  • Scopes
  • Scope inheritance
  • Tags and filtering
  • Dependency graph and --impacted
  • Aliases and groups
  • Introspection commands