Development tasks in a Monorepo
The vast majority of development workflows look like this:
- Open a repository
- Run a
devtask while they develop - At the end of the day, shut down the
devtask and close the repository.
dev will likely be the most frequently run task in your repository, so getting it right is important.
Types of dev tasks
dev tasks come in many shapes and sizes:
- Running a local development server for a web app
- Running
nodemon(opens in a new tab) to re-run a backend process every time code changes - Running tests in
--watchmode
Setup with Turborepo
You should specify your dev task like this in your turbo.json.
{
"pipeline": {
"dev": {
"cache": false,
"persistent": true
}
}
}Since dev tasks don't produce outputs, outputs is empty. dev tasks are also unique in that you
rarely want to cache them, so we set cache as false.
We also set persistent to true, because dev tasks are long-running tasks, and we want to ensure
that it doesn't block any other task from executing.
Setting up package.json
You should also provide a dev task in your root package.json:
{
"scripts": {
"dev": "turbo run dev"
}
}This enables developers to run the task directly from their normal task runner.
Running tasks before dev
In some workflows, you'll want to run tasks before you run your dev task. For instance, generating code or running a db:migrate task.
In these cases, use dependsOn to say that any codegen or db:migrate tasks should be run before dev is run.
{
"pipeline": {
"dev": {
"dependsOn": ["codegen", "db:migrate"],
"cache": false
},
"codegen": {
"outputs": ["./codegen-outputs/**"]
},
"db:migrate": {
"cache": false
}
}
}Then, in your app's package.json:
{
"scripts": {
// For example, starting the Next.js dev server
"dev": "next",
// For example, running a custom code generation task
"codegen": "node ./my-codegen-script.js",
// For example, using Prisma
"db:migrate": "prisma db push"
}
}This means that users of your dev task don't need to worry about codegen or migrating their database - it gets handled for them before their development server even starts.
Running dev only in certain workspaces
Let's assume you want to run the dev task in the docs workspace, located at <root>/apps/docs.
turbo can infer the workspace from your directory, so if you run:
cd <root>/apps/docs
turbo run devturbo will automatically pick up that you're in the docs workspace and run the dev task.
To run the same task from any other location in the repository, use --filter syntax.
For example:
turbo run dev --filter docsUsing environment variables
While developing, you'll often need to use environment variables. These let you customize the behavior of your program - for instance, pointing to a different DATABASE_URL in development and production.
We recommend using a library called dotenv-cli (opens in a new tab) to solve this problem.
We want every dev to have a great experience using Turbo. The approach documented below does not live up to those standards.
We're working on a first-class solution to this problem - but while you wait, here's the next-best solution.
Tutorial
- Install
dotenv-cliin your root workspace:
# Installs dotenv-cli in the root workspace
npm add dotenv-cli- Add a
.envfile to your root workspace:
├── apps/
├── packages/
+ ├── .env
├── package.json
└── turbo.jsonAdd any environment variables you need to inject:
DATABASE_URL=my-database-url- Inside your root
package.json, add adevscript. Prefix it withdotenvand the--argument separator:
{
"scripts": {
"dev": "dotenv -- turbo run dev"
}
}This will extract the environment variables from .env before running turbo run dev.
- Now, you can run your dev script:
npm run devAnd your environment variables will be populated! In Node.js, these are available on process.env.DATABASE_URL.
You should also add your environment variables to your turbo.json if you're using them to build your app.