Development tasks in a Monorepo
The vast majority of development workflows look like this:
- Open a repository
- Run a
dev
task while they develop - At the end of the day, shut down the
dev
task 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
to re-run a backend process every time code changes - Running tests in
--watch
mode
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 docs
Will 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-cli
in your root workspace:
# Installs dotenv-cli in the root workspace
npm add dotenv-cli
- Add a
.env
file to your root workspace:
├── apps/
├── packages/
+ ├── .env
├── package.json
└── turbo.json
Add any environment variables you need to inject:
DATABASE_URL=my-database-url
- Inside your root
package.json
, add adev
script. Prefix it withdotenv
and 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 dev
And 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.