How to Run a Specific Job in a GitHub Actions Workflow Using `act --job`
Use the -j or --job flag followed by the job ID to execute only that job and its dependencies, skipping all other jobs in the workflow.
The nektos/act CLI tool allows you to run GitHub Actions workflows locally for testing and debugging. When you want to iterate on a single job without executing the entire workflow graph, the --job flag provides precise control over what runs on your machine.
Flag Definition and CLI Parsing
The --job flag is registered in the root command definition located in cmd/root.go. At line 73, the flag is declared with a short alias -j:
rootCmd.Flags().StringP("job", "j", "", "run a specific job ID")
When you execute a run command, the value is retrieved inside newRunCommand at lines 56-57:
jobID, err := cmd.Flags().GetString("job")
If a non-empty jobID is provided, act bypasses the default full-workflow planning and instead builds a targeted execution plan.
Building a Filtered Execution Plan
The filtering logic resides in cmd/root.go where the planner switches modes based on the presence of a job ID. At lines 99-100 and again at lines 51-54, the code checks for the flag and calls PlanJob:
if jobID != "" {
filterPlan, plannerErr = planner.PlanJob(jobID)
}
The PlanJob method in pkg/model/planner.go (lines 31-45) constructs a plan containing only the requested job and its required predecessors:
func (wp *workflowPlanner) PlanJob(jobName string) (*Plan, error) {
plan := new(Plan)
for _, w := range wp.workflows {
stages, err := createStages(w, jobName)
// ...
}
return plan, lastErr
}
Unlike the standard planning mode which executes all jobs triggered by an event, PlanJob invokes createStages with a specific target, resulting in a minimal execution graph.
Dependency Resolution Algorithm
The heavy lifting occurs in createStages within pkg/model/planner.go (lines 44-78). This function performs two critical operations:
-
Collects transitive dependencies – It recursively follows the
needsgraph of the requested job, building a complete list of all jobs that must run first. -
Constructs execution stages – Jobs with satisfied dependencies are grouped into stages that run in parallel, respecting the dependency order.
Key implementation details from the source:
// Gather the transitive closure of required jobs
jobDependencies := make(map[string][]string)
for len(jobIDs) > 0 {
// ...
jobDependencies[jID] = job.Needs()
// ...
}
// Construct stages respecting dependencies
for len(jobDependencies) > 0 {
stage := new(Stage)
for jID, jDeps := range jobDependencies {
if listInStages(jDeps, stages...) { // all deps already staged?
stage.Runs = append(stage.Runs, &Run{Workflow: w, JobID: jID})
delete(jobDependencies, jID)
}
}
// ...
}
The dependency data originates from the Job struct defined in pkg/model/workflow.go (line 196), which includes the Needs []string field:
type Job struct {
ID string
Needs []string // ← list of job IDs this job depends on
// ...
}
The Needs() method returns this slice, enabling the planner to walk the dependency graph and ensure prerequisites execute before the target job.
Practical Usage Examples
Before targeting a specific job, enumerate available job IDs using the list command:
# List all jobs defined in the workflows
act --list
Execute a single job by its ID. This automatically includes any jobs defined in its needs configuration:
# Run only the job named 'test' (and any jobs it needs)
act -j test
Combine the job filter with an explicit event trigger when workflows have multiple entry points:
# Trigger on push event but only run the 'build' job
act push -j build
Preview the execution plan without running containers using the dry-run flag:
# Debug the plan (shows the stages that will be executed)
act -j lint --dryrun
Summary
- The
--job(or-j) flag innektos/actlimits execution to a specific job ID and its dependency chain. - Flag parsing occurs in
cmd/root.go, while plan construction happens inpkg/model/planner.govia thePlanJobmethod. - The
createStagesalgorithm resolves transitive dependencies by traversing theneedsgraph defined inpkg/model/workflow.go. - Jobs are organized into parallel stages where all dependencies within a stage are satisfied before proceeding to the next stage.
- This targeted approach significantly speeds up local debugging by skipping unrelated workflow jobs.
Frequently Asked Questions
How do I find the correct job ID to use with act --job?
Run act --list to display all available job IDs from your workflow files. The ID corresponds to the key name under the jobs: section in your YAML file, not the name: field. According to the implementation in cmd/list.go, this enumerates all jobs the planner can detect.
Does act --job run dependent jobs automatically?
Yes. When you specify a job ID, act builds a filtered plan that includes the target job plus every job listed in its needs array, recursively. As implemented in pkg/model/planner.go, the createStages function calculates the transitive closure of dependencies, ensuring prerequisites execute first.
Can I run multiple specific jobs at once using the flag?
No. The --job flag accepts a single string value and calls planner.PlanJob with that specific ID. To run multiple unrelated jobs, you must execute separate act commands or allow the default full-plan execution and use other filtering mechanisms like --graph visualization.
What happens if I specify a job ID that does not exist?
If the job ID is not found in the workflow files, PlanJob in pkg/model/planner.go returns an error, and act exits with a planner error before attempting to run any containers. The CLI validates the job exists during the planning phase at lines 51-54 and 99-100 of cmd/root.go.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →