Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Monorepo Generation

To set up a basic monorepo with default settings, we can just run the command sketch ts monorepo. But we can also create a package preset and use that for the root package of the monorepo.

This is a more customized configuration for the root package:

typescript:
  # By default, typescript and oxlint would be added to
  # the root package's dependencies
  no_default_deps: true

  # Pnpm is the default, and if selected, it will generate
  # a pnpm-workspace.yaml file
  package_manager: pnpm

  pnpm_presets:
    base:
      # All the dirs listed here will be created automatically
      # when new monorepos are created
      packages:
        - packages/*
      onlyBuiltDependencies:
        - esbuild
      minimumReleaseAge: 1440

  package_presets:
    # Defining a preset for the root package
    root:
      name: workspace

      package_json:
        workspaces:
          # All dirs listed here are also created automatically
          # unless they contain '{', '[', '?' or '!'
          - apps/**/test
        license: Apache-2.0
        devDependencies:
          husky: ^9.0.0

      # The tsconfig files to generate at the root.
      # If left empty, defaults will be used.
      ts_config:
        - output: tsconfig.options.json
          config:
            compilerOptions:
              verbatimModuleSyntax: true
              strict: true

        - output: tsconfig.json
          config:
            files: []

      # Literal oxlint configuration to generate at the root
      # of the workspace.
      # Can be set to `true` to use defaults.
      oxlint:
        plugins: ["unicorn", "typescript", "oxc"]

Adding Templates

You can also use the with_templates field to automatically generate a certain file structure when the monorepo is generated.

Let's say, for example, that every time that you create a new monorepo, you always want to create a docker directory with a basic dev.dockerfile inside of it, so that you can quickly create a dev environment using docker.

To do that, we add this to the root package's definition:

      with_templates:
        - templates:
            # Relative path from the root of the package
            - output: docker/dev.dockerfile
              template:
                name: dev_dockerfile
                content: |
                  FROM node:23-alpine

                  COPY . .
                  EXPOSE {{ docker_dev_port }}
                  CMD ["npm", "run", "dev"]

vars:
  docker_dev_port: 5173

ℹ️ You can also use --with-template <PRESET_ID|id=TEMPLATE_ID,output=PATH> as a flag to add more templates or templating presets when generating a new package.

Hooks

We can define some commands (which can also be templates) to execute before and/or after generating the new monorepo:

    # Commands to run before generation, from the root of the new project
    hooks_pre:
      - command:
          # Inlining a new template definition here,
          # but as always, we can use stored templates too
          name: pre_hook
          content: "echo '{{ greeting }}' > pre.txt"
        context:
          greeting: hi

    # Commands to run after generation, from the root of the new project
    hooks_post:
      - command:
          name: post_hook
          content: "echo '{{ greeting }}' > post.txt"
        context:
          greeting: hi

Example

So after setting everything up, we run the command

sketch ts monorepo --root-package root --pnpm base

And get this tree output:

├── .oxlintrc.json
├── apps
│   └── test
├── docker
│   └── dev.dockerfile
├── package.json
├── packages
├── pnpm-workspace.yaml
├── tsconfig.json
└── tsconfig.options.json

ℹ️ You can use the -i flag to install dependencies for the root package after creating the new monorepo.