apps/docs/content/docs/guides/generating-code.mdx
Splitting your monorepo into packages is a great way to organize your code, speed up tasks, and improve the local development experience. With Turborepo's code generation, it's easy to generate new source code for packages, modules, and even individual UI components in a structured way that integrates with the rest of your repository.
Add a new, empty app or package to your monorepo.
turbo gen workspace
View all available options for gen workspace.
You can use an existing workspace as a template for your new app or package. This works for both workspaces within your existing monorepo, and remote workspaces from other repositories (specified via GitHub URL).
Create a new package in your monorepo by copying from an existing package in your repo.
turbo gen workspace --copy
Create a new workspace in your monorepo by copying from a remote package.
turbo gen workspace --copy https://github.com/vercel/turborepo/tree/main/examples/with-tailwind/packages/tailwind-config
View all available options for gen workspace --copy.
If a built-in generator does not fit your needs, you can create your own custom generator using Plop configurations. Turborepo will automatically detect any generator configurations within your repo, and make them available to run from the command line.
<Callout type="info"> While Turborepo Generators are built on top of Plop, they don't require `plop` to be installed as a dependency in your repo. </Callout>While Turborepo understands all Plop configuration options and features, it provides a few additional features to improve the experience of writing generators within a repo configured with Turborepo.
load them within a single configuration file)--root flag)plop is not required to be installed as a dependency of your repoTo build and run a custom generator, run the following command from anywhere within your monorepo using Turborepo.
turbo gen
You'll be prompted to select an existing generator or to create one if you don't have any yet. You can also create your configuration
manually at turbo/generators/config.ts (or config.js) at the root of your repo - or within any workspace.
For example, the following illustrates a monorepo with three locations for generators:
<PackageManagerTabs> <Tab value="pnpm"> <Files> <Folder name="apps" defaultOpen> <Folder name="docs"> <File name="package.json" /> </Folder> <Folder name="web" defaultOpen> <File name="package.json" /> <Folder name="turbo" green defaultOpen> <Folder name="generators"> <File name="config.ts" /> <File name="templates" /> </Folder> </Folder> </Folder> </Folder> <Folder name="packages" defaultOpen> <Folder name="ui" defaultOpen> <File name="package.json" /> <Folder name="turbo" green defaultOpen> <Folder name="generators"> <File name="config.ts" /> <File name="templates" /> </Folder> </Folder> </Folder> </Folder> <Folder name="turbo" green defaultOpen> <Folder name="generators"> <File name="config.ts" /> <File name="templates" /> </Folder> </Folder> <File name="package.json" /> <File name="package-lock.yaml" /> <File name="pnpm-workspace.yaml" /> <File name="turbo.json" /> </Files> </Tab> <Tab value="yarn"> <Files> <Folder name="apps" defaultOpen> <Folder name="docs"> <File name="package.json" /> </Folder> <Folder name="web" defaultOpen> <File name="package.json" /> <Folder name="turbo" green defaultOpen> <Folder name="generators"> <File name="config.ts" /> <File name="templates" /> </Folder> </Folder> </Folder> </Folder> <Folder name="packages" defaultOpen> <Folder name="ui" defaultOpen> <File name="package.json" /> <Folder name="turbo" green defaultOpen> <Folder name="generators"> <File name="config.ts" /> <File name="templates" /> </Folder> </Folder> </Folder> </Folder> <Folder name="turbo" green defaultOpen> <Folder name="generators"> <File name="config.ts" /> <File name="templates" /> </Folder> </Folder> <File name="package.json" /> <File name="yarn.lock" /> <File name="turbo.json" /> </Files> </Tab> <Tab value="npm"> <Files> <Folder name="apps" defaultOpen> <Folder name="docs"> <File name="package.json" /> </Folder> <Folder name="web" defaultOpen> <File name="package.json" /> <Folder name="turbo" green defaultOpen> <Folder name="generators"> <File name="config.ts" /> <File name="templates" /> </Folder> </Folder> </Folder> </Folder> <Folder name="packages" defaultOpen> <Folder name="ui" defaultOpen> <File name="package.json" /> <Folder name="turbo" green defaultOpen> <Folder name="generators"> <File name="config.ts" /> <File name="templates" /> </Folder> </Folder> </Folder> </Folder> <Folder name="turbo" green defaultOpen> <Folder name="generators"> <File name="config.ts" /> <File name="templates" /> </Folder> </Folder> <File name="package.json" /> <File name="package-lock.json" /> <File name="turbo.json" /> </Files> </Tab> <Tab value="bun"> <Files> <Folder name="apps" defaultOpen> <Folder name="docs"> <File name="package.json" /> </Folder> <Folder name="web" defaultOpen> <File name="package.json" /> <Folder name="turbo" green defaultOpen> <Folder name="generators"> <File name="config.ts" /> <File name="templates" /> </Folder> </Folder> </Folder> </Folder> <Folder name="packages" defaultOpen> <Folder name="ui" defaultOpen> <File name="package.json" /> <Folder name="turbo" green defaultOpen> <Folder name="generators"> <File name="config.ts" /> <File name="templates" /> </Folder> </Folder> </Folder> </Folder> <Folder name="turbo" green defaultOpen> <Folder name="generators"> <File name="config.ts" /> <File name="templates" /> </Folder> </Folder> <File name="package.json" /> <File name="bun.lock" /> <File name="turbo.json" /> </Files> </Tab> </PackageManagerTabs>Generators created within workspaces are automatically run from the workspace root, not the repo root, nor the location of the generator configuration.
This makes your generators more simple to write. Creating a file at [workspace-root] only needs to be specified as <file> rather than ../../<file>.
Learn more about creating custom generators using Plop.
A generator configuration file is a function that returns a Plop configuration object. The configuration object is used to define the generator's prompts, and actions.
In its simplest form, a generator configuration file looks like:
import type { PlopTypes } from "@turbo/gen";
export default function generator(plop: PlopTypes.NodePlopAPI): void {
// create a generator
plop.setGenerator("Generator name", {
description: "Generator description",
// gather information from the user
prompts: [
...
],
// perform actions based on the prompts
actions: [
...
],
});
}
Prompts are written using Plop prompts and are used to gather information from the user.
Actions can use built-in Plop actions, or custom action functions that you define yourself:
import type { PlopTypes } from "@turbo/gen";
const customAction: PlopTypes.CustomActionFunction = async (answers) => {
// fetch data from a remote API
const results = await fetchRemoteData();
// add the response to the answers, making this data available to actions
answers.results = results;
// return a status string
return 'Finished data fetching!';
}
export default function generator(plop: PlopTypes.NodePlopAPI): void {
// create a generator
plop.setGenerator("Generator name", {
description: "Generator description",
prompts: [
...
],
actions: [
customAction
...
],
});
}
When running actions, Turborepo automatically injects a turbo object into the answers data. This gives your templates and custom actions access to useful information about the repository without needing to discover it yourself.
In Handlebars templates, access the variables using double curly braces:
// Generated at {{ turbo.paths.root }}/src/components
In custom action functions, the turbo object is available on the answers parameter:
import type { PlopTypes } from "@turbo/gen";
export default function generator(plop: PlopTypes.NodePlopAPI): void {
plop.setGenerator("example", {
description: "An example using turbo variables",
prompts: [],
actions: [
async (answers) => {
const { turbo } = answers;
console.log(`Monorepo root: ${turbo.paths.root}`);
return "Done!";
},
],
});
}
The available variables are documented in the @turbo/gen reference.
Once you have created your generator configuration file, you can skip the selection prompt and directly run a specified generator with:
turbo gen [generator-name]
Arguments can also be passed directly to the generator prompts using --args
turbo gen [generator-name] --args answer1 answer2 ...
See bypassing prompts in the Plop documentation for more information.
View all available options for gen.