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 nodemonto 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
    }
  }
}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.
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
To run a dev task in only certain workspaces, you should use the --filter syntax. For example:
turbo run dev --filter docsWill only run dev in the workspace named docs.
Using 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 to solve this problem.
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.