No description
Find a file
2026-03-29 17:51:27 +02:00
scripts version 0.1.0-pre.1+MR 2026-03-21 23:53:53 +01:00
src version 0.1.0-pre.1+MR 2026-03-21 23:53:53 +01:00
template version 0.1.0-pre.2 2026-03-24 22:46:06 +01:00
tests adding tests 2026-03-24 20:55:59 +01:00
.gitignore ignoring bun.lock 2026-03-22 11:44:46 +01:00
CHANGELOG.md version0.1.1 2026-03-29 17:50:47 +02:00
LICENSE initializing the package from @temir.ra/ts-lib 2026-03-03 23:11:18 +01:00
package.json version0.1.1 2026-03-29 17:50:47 +02:00
README.md version 0.1.0-pre.2 2026-03-24 22:46:06 +01:00
tsconfig.build.json initializing the package from @temir.ra/ts-lib 2026-03-03 23:11:18 +01:00
tsconfig.json version 0.1.0-pre.2 2026-03-24 22:46:06 +01:00

Introduction

A template for monorepos using workspaces. Provides a shared root configuration with unified dependency management and cross-workspace imports by package name.

The following templates are available in this ecosystem:

Template Purpose
create-ts-lib TypeScript library distributed via registry
create-hono-server Bun/Hono HTTP server
create-hono-spa Frontend SPA as a Hono sub-app library
create-monorepo Monorepo root (this template)

Table of Contents

  1. Quick Start
  2. AI Assistant Context
  3. Documentation
    1. package.json
    2. Cross-workspace Dependencies
    3. Scaffolding Patterns
      1. Library
      2. Server
      3. Server + SPA
      4. Full-Stack with Shared Types
  4. DevOps
    1. Change Management
    2. Publish

Quick Start

bun create caches the template package - a newer published version will not be picked up automatically. Pin the version or clear the cache to use the latest.

# placeholder:
    # <MONOREPO: <MONOREPO>
    # <@_VERSION: <@_VERSION>

# identify the latest version of the template package as <@_VERSION.
bun info "@temir.ra/create-monorepo" version
# create a new library from the template version
bun create --no-install --no-git "@temir.ra/monorepo<@_VERSION>" <MONOREPO>

# or

# clear package manager cache to ensure the latest template version is used
bun pm cache rm
# create a new library from the latest template version
bun create --no-install --no-git "@temir.ra/monorepo" <MONOREPO>

# dependencies must be installed manually
cd <MONOREPO>
bun install

AI Assistant Context

To generate an AI coding assistant context file for this project:

Generate an AI coding assistant context file. Analyze the project structure and source files, using this README as the primary reference for architecture and conventions. Give particular attention to: the workspace symlink mechanism and how cross-package imports resolve by package name without path aliases, the workspace:* protocol and its publish-time version replacement behaviour, and the scaffolding patterns and which templates are combined for each scenario.

Documentation

The following sections explain the configurations and conventions baked into the generated package. Useful when adapting the generated monorepo to fit specific needs.

package.json

{
  "name": "",
  "version": "0.0.0",

  "description": "",
  "author": "",
  "license": "",

  // prevents publishing the root to a registry; only workspace packages are published
  "private": true,

  // glob patterns matching directories that each contain a package.json;
  // the execution environment installs all workspace dependencies into the shared root node_modules/
  // and symlinks each package by its name field for cross-workspace imports
  "workspaces": [
    "packages/*"
  ],

  "scripts": {

    // runs the named script in every workspace package that defines it,
    // in dependency order (dependents run after the packages they depend on)
    "clean": "bun run --filter '*' --parallel clean",
    "build": "bun run --filter '*' --parallel build",
    "typecheck": "bun run --filter '*' --parallel typecheck",
    "tests": "bun run --filter '*' --parallel tests"

  },

}

Each workspace package has its own package.json with its specific dependencies and scripts.

<MONOREPO>/
├── package.json          ← root
└── packages/
    ├── pkg-a/
    │   ├── package.json
    │   └── ...
    └── pkg-b/
        ├── package.json
        └── ...

The execution environment installs all workspace packages into a single shared node_modules/ at the root and symlinks each workspace package by its name field. Cross-workspace imports resolve by package name without path aliases or module mapping.

Cross-workspace Dependencies

To use one workspace package from another, declare it as a dependency using the workspace: protocol:

// packages/pkg-a/package.json
{
  "dependencies": {

    // workspace: resolves to the local package instead of fetching from a registry;
    // workspace:* tracks the exact local version;
    // workspace:^ is replaced by ^version on publish, tracking the semver range in the registry
    "@scope/pkg-b": "workspace:*"

  }
}

Run bun install after adding the entry. The execution environment creates the symlink in node_modules/ so imports resolve by package name at runtime and at the type level - no path alias or paths mapping required.

Scaffolding Patterns

Scaffold the monorepo first, then add packages inside it. After scaffolding each package, update its package.json with the correct name, version, description, author, license, and repository fields. To wire cross-workspace dependencies, add the workspace:* entry to the consuming package's package.json and run bun install from the monorepo root.

Library

<monorepo>/
└── packages/
    └── my-lib/        ← create-ts-lib
bun create --no-install --no-git "@temir.ra/monorepo" <monorepo>
cd <monorepo>
bun create --no-install --no-git "@temir.ra/ts-lib" packages/my-lib
bun install

create-ts-lib

Starting point for any package distributed via a registry. See the full documentation at @temir.ra/create-ts-lib.

  • Dual tsconfig: tsconfig.json (dev, bundler resolution, includes tests/ + scripts/) and tsconfig.build.json (prod, nodenext, src/ only, emits JS + .d.ts)
  • exports conditions: entrypoint (custom, source entry for the bundle script), types, browser (bundled output), import (compiled ESM)
  • imports field: #src/*.js./src/*.ts - runtime alias for dev.ts, tests/, scripts/ only
  • Build metadata: scripts/buildinfo.ts generates buildinfo.txt (version + git hash) as a prebuild hook
  • Bundle script: scripts/build-lib-bundle.ts bundles via Bun; supports CDN specifier rewriting via cdn-rewrite-map.json
  • Asset resolution contract: assets under assets/@scope/lib-name/, accessed via import.meta.url + fetch()
  • Optional CLI entry point via bin field and build:cli-bundle script

Server

<monorepo>/
└── packages/
    └── server/        ← create-hono-server
bun create --no-install --no-git "@temir.ra/monorepo" <monorepo>
cd <monorepo>
bun create --no-install --no-git "@temir.ra/hono-server" packages/server
bun install

create-hono-server

Starting point for any HTTP backend. See the full documentation at @temir.ra/create-hono-server.

  • createAppHost(options) - configures and returns a Hono<AppEnv> instance
  • Built-in middleware pipeline: Logging, requestId, RequestLogger, compress, secureHeaders
  • Built-in endpoints: /health, /buildinfo, OpenAPI spec, Scalar UI
  • endpointGroups - mounts additional Hono sub-apps; integration point for SPA packages
  • AppEnv - exported, extensible context type; extend it to carry custom variables through the context
  • startServerHost(options) - wraps Bun.serve(), default port 7200, graceful shutdown on SIGINT/SIGTERM

Server + SPA

<monorepo>/
└── packages/
    ├── server/        ← create-hono-server
    └── spa/           ← create-hono-spa
bun create --no-install --no-git "@temir.ra/monorepo" <monorepo>
cd <monorepo>
bun create --no-install --no-git "@temir.ra/hono-server" packages/server
bun create --no-install --no-git "@temir.ra/hono-spa" packages/spa
bun install

Add the SPA as a dependency of the server, then reinstall:

// packages/server/package.json
{
  "dependencies": {
    "@scope/spa": "workspace:*"
  }
}
bun install

create-hono-spa

Starting point for a frontend SPA distributed as a Hono sub-app library. See the full documentation at @temir.ra/create-hono-spa.

  • createSpa(options) - returns a Hono sub-app serving the SPA shell
  • /app/* wildcard handles client-side routing; <base href> patched at request time from basePath and path
  • Assets resolved via import.meta.url; no file copying or static serving config needed on the consuming server
  • PWA scaffold in assets/: index.html, favicon.svg, manifest.webmanifest, screenshots
  • Distributed as a library (exports + dist/ + assets/); consumed via workspace:* in the server

Full-Stack with Shared Types

<monorepo>/
└── packages/
    ├── server/        ← create-hono-server
    ├── spa/           ← create-hono-spa
    └── types/         ← create-ts-lib
bun create --no-install --no-git "@temir.ra/monorepo" <monorepo>
cd <monorepo>
bun create --no-install --no-git "@temir.ra/hono-server" packages/server
bun create --no-install --no-git "@temir.ra/hono-spa" packages/spa
bun create --no-install --no-git "@temir.ra/ts-lib" packages/types
bun install

Add the types package as a dependency of both the server and the SPA, then reinstall:

// packages/server/package.json  and  packages/spa/package.json
{
  "dependencies": {
    "@scope/types": "workspace:*"
  }
}
bun install

DevOps

# remove dist/ and tsconfig.build.tsbuildinfo
bun run clean

# remove dist/ only
bun run clean:dist

# remove tsconfig.build.tsbuildinfo only
bun run clean:tsbuildinfo

# compile + bundle
bun run build

# create a new test monorepo in example/
bun run dist/cli.bundle.js -- example

Change Management

  1. Create a new branch for the change.
  2. Make the changes and commit.
  3. Bump the version in package.json.
  4. Add an entry for the new version in CHANGELOG.md.
  5. Pull request the branch.
  6. After merge, run bun run build - ensures artifacts are current before publish.
  7. Publish.

Publish

See the following sources to configure the target registry and authentication.

⚠️ Package Scope and the authentication for the target registry must be aligned.

npmjs.org

Publish to the public npm registry.

# authenticate
npm login
# publish
bun publish --registry https://registry.npmjs.org/ --access public

Custom registry

# placeholder:
    # <SCOPE_WITHOUT_AT: <SCOPE_WITHOUT_AT>
    # <REGISTRY_URL: <REGISTRY_URL>
    # <BUN_PUBLISH_AUTH_TOKEN: <BUN_PUBLISH_AUTH_TOKEN>

~/.bunfig.toml or bunfig.toml:

[install.scopes]
"<SCOPE_WITHOUT_AT>" = { url = "<REGISTRY_URL>", token = "$BUN_PUBLISH_AUTH_TOKEN" }
# authenticate
$env:BUN_PUBLISH_AUTH_TOKEN = "<BUN_PUBLISH_AUTH_TOKEN>"
# publish
bun publish