Skip to content
Tutorial 3/8: Configure tasks for your projects

Help me configure tasks (build, test, lint, serve) for my Nx workspace projects.

Use my existing workspace and projects for hands-on examples.

Show me what tasks already exist by running for one of my projects. Then help me add or configure tasks using package.json scripts or project.json targets, set up task dependencies with , and verify with .

Stay on-topic: only teach what's covered on this page. Do not introduce concepts from later tutorials.

Tutorial: https://canary.nx.dev/docs/getting-started/tutorials/configuring-tasks.md

Help me configure tasks (build, test, lint, serve) for my Nx workspace projects.

Use my existing workspace and projects for hands-on examples.

Show me what tasks already exist by running for one of my projects. Then help me add or configure tasks using package.json scripts or project.json targets, set up task dependencies with , and verify with .

Stay on-topic: only teach what's covered on this page. Do not introduce concepts from later tutorials.

Tutorial: https://canary.nx.dev/docs/getting-started/tutorials/configuring-tasks.md

Every project needs tasks: build, test, lint, serve. Nx needs to know about your tasks so it can run them, cache the results, and orchestrate them in the correct order across your workspace. If you don't have a workspace yet, see Crafting Your Workspace.

The examples below use Vite and Vitest, but the concepts apply to any tool. Substitute your own build and test commands as needed.

A task is a named action that Nx can run for a project, like build, test, or lint. Each task belongs to a specific project and is referred to as <project>:<task>:

Terminal window
nx run my-app:build

You'll learn more about running tasks in the Running Tasks tutorial.

The simplest way to define tasks is with package.json scripts. Nx picks these up automatically:

apps/my-app/package.json
{
"name": "my-app",
"scripts": {
"build": "vite build",
"test": "vitest run",
},
}

If your workspace already has package.json scripts, Nx can run them immediately, no additional configuration needed.

If you prefer to keep task definitions out of package.json (e.g., you don't want scripts published to npm) or for non-JavaScript projects, define tasks in a project.json file using the targets property:

apps/my-app/project.json
{
"name": "my-app",
"targets": {
"build": {
"command": "vite build",
},
"test": {
"command": "vitest run",
},
},
}

The command property runs a shell command, similar to a package.json script. You can also use executors for more advanced task runners provided by Nx plugins, but command works for most cases.

In a monorepo, tasks often need to run in a specific order. For example, before building an app, you need to build the libraries it depends on.

The dependsOn property defines this ordering:

nx.json
{
"targetDefaults": {
"build": {
"dependsOn": ["^build"],
},
},
}

The ^ prefix means "the same task on projects this project depends on." So nx build my-app will first build all of my-app's dependencies, then build my-app itself.

You can also define dependencies without ^ for tasks within the same project:

apps/my-app/package.json
{
"scripts": {
"build": "vite build",
"generate-api-types": "openapi-generator generate -i api.yaml -o src/api",
},
"nx": {
"targets": {
"build": {
"dependsOn": ["generate-api-types"],
},
},
},
}

Here, build always runs generate-api-types first within the same project.

Some tasks, like development servers, never exit. If another task depends on a long-running process, it would wait forever. Mark these tasks as continuous so Nx starts them alongside their dependents instead of waiting for them to finish:

apps/my-app/package.json
{
"scripts": {
"dev": "vite dev",
"e2e": "playwright test",
},
"nx": {
"targets": {
"dev": {
"continuous": true,
},
"e2e": {
"dependsOn": ["dev"],
},
},
},
}

Running nx e2e my-app starts the dev server and then runs the E2E tests against it.

When many projects share the same task configuration, defining it in every project.json is tedious. The targetDefaults property in nx.json lets you set defaults for all projects at once:

nx.json
{
"targetDefaults": {
"build": {
"dependsOn": ["^build"],
},
},
}

Individual projects can still override these defaults when needed. The cascade order is: project-level config > target defaults > defaults.

For more on reducing configuration, see Reducing Configuration Boilerplate.