GitHub Actions study materials
GitHub Actions study resources

GitHub Actions practice questions

One question at a time. Build your GitHub Actions understanding.

First 50 of 198 questions. Each one lists the choices, the correct answer, and an explanation. The checker at the top of this page saves progress in this browser when it is available.

Continue in the practice tool above to load more questions, 50 at a time.

Question 1Workflow creation

In a GitHub Actions workflow file, which top-level key holds the collection of jobs that the run will execute?

  1. runs-on
  2. steps
  3. jobs Correct answer.
  4. on

Explanation

The `jobs` key is the top-level map where each named job is defined; every workflow that does work must declare at least one entry under it. `steps` and `runs-on` are properties of an individual job, and `on` declares the triggering events.

Question 2Workflow creation

Which file location does GitHub read to find a workflow definition for a repository?

  1. .github/build/workflow.yml
  2. .github/workflows/build.yml Correct answer.
  3. workflows/.github/build.yml
  4. .github/actions/build.yml

Explanation

GitHub loads workflow files from the `.github/workflows` directory at the repository root, and any `.yml` or `.yaml` file there is treated as a workflow. Other directories are ignored for workflow discovery, and a workflow can also be placed in an organization-level `.github` repository.

Question 3Workflow creation

A workflow must run both when a pull request targets `main` and when a release is published. Which `on` configuration expresses that?

  1. on: pull_request: branches: [main] release: published
  2. on: [pull_request, release, main]
  3. on: pull_request: branches: [main] release: types: [published] Correct answer.
  4. on: pull_request: main releases: published

Explanation

Each trigger is a key under `on`, and each trigger accepts a configuration map. `pull_request` supports a `branches` filter, while `release` uses `types` to select activity types such as `published`.

Question 4Workflow creation

Which expression correctly references a secret named `DEPLOY_TOKEN` inside a workflow step?

  1. ${{ secret.DEPLOY_TOKEN }}
  2. ${{ env.secrets.DEPLOY_TOKEN }}
  3. ${{ vars.DEPLOY_TOKEN }}
  4. ${{ secrets.DEPLOY_TOKEN }} Correct answer.

Explanation

Secrets are exposed through the `secrets` context, which is singular in name and plural only as the context key. The `vars` context holds configuration variables, which are stored separately from secrets.

Question 5Workflow creation

What is the default behavior of a job when one of its steps exits with a non-zero status?

  1. The job pauses and waits for a manual approval.
  2. The remaining steps in that job are skipped and the job is marked failed. Correct answer.
  3. The remaining steps still run and only the final step determines the job result.
  4. The workflow retries the failed step once before continuing.

Explanation

By default a step that fails causes the job to stop executing further steps and to report failure. You can change this per step with `continue-on-error: true` or with a conditional expression on later steps.

Question 6Workflow creation

Which job-level key controls the maximum number of minutes a job may run before it is cancelled?

  1. job-timeout
  2. timeout-minutes Correct answer.
  3. timeout
  4. max-duration

Explanation

`timeout-minutes` is set at the job or step level and caps the runtime in minutes. The default job limit is 360 minutes, and a step can also define its own timeout.

Question 7Workflow creation

A job must not start until two other jobs, `build` and `lint`, have both completed successfully. Which key expresses this?

  1. needs: [build, lint] Correct answer.
  2. depends-on: [build, lint]
  3. requires: [build, lint]
  4. after: [build, lint]

Explanation

`needs` declares job dependencies, and a job with `needs` waits for every listed job to succeed before it runs. If any listed job fails or is skipped, the dependent job is skipped by default.

Question 8Workflow creation

Which `runs-on` value selects a GitHub-hosted runner running the latest Ubuntu image?

  1. linux-latest
  2. hosted-ubuntu
  3. ubuntu-22.04-latest
  4. ubuntu-latest Correct answer.

Explanation

GitHub-hosted runner labels follow the pattern `<os>-latest` or a pinned version such as `ubuntu-22.04`. `ubuntu-latest` therefore resolves to the current default Ubuntu image.

Question 9Workflow creation

A step should run only when the workflow is triggered by a push event. Which condition accomplishes this?

  1. if: github.event_name == 'push' Correct answer.
  2. if: event.name == 'push'
  3. if: github.trigger == 'push'
  4. if: github.event == 'push'

Explanation

The `github` context exposes `event_name`, which holds the name of the event that triggered the run. Comparing it to a string literal inside `if` is the standard way to gate a step by trigger.

Question 10Workflow creation

What does the `strategy.matrix` key allow a workflow author to do?

  1. Store encrypted values for use during the run.
  2. Restrict a job to run on a specific operating system only.
  3. Expand one job definition into multiple parallel job runs over combinations of values. Correct answer.
  4. Define a sequence of steps that must run in strict order.

Explanation

A matrix generates one job per combination of the listed values, so a single job definition can be tested across several versions or platforms. `include` and `exclude` refine which combinations are produced.

Question 11Workflow creation

A matrix job should be allowed to fail for an experimental Node.js version without failing the whole workflow. Which setting achieves this?

  1. continue-on-error: ${{ matrix.experimental }} Correct answer.
  2. fail-fast: false
  3. allow-failure: true
  4. if: success()

Explanation

`continue-on-error` accepts an expression, so it can be driven by a matrix value such as `experimental`. When it evaluates to true, that job's failure does not fail the workflow run.

Question 12Workflow creation

Which syntax passes the output `version` from a job named `build` into a later job?

  1. ${{ jobs.build.outputs.version }}
  2. ${{ build.outputs.version }}
  3. ${{ needs.build.outputs.version }} Correct answer.
  4. ${{ steps.build.outputs.version }}

Explanation

Outputs from upstream jobs are read through the `needs` context, keyed by the job identifier and then by the output name. The producing job must declare the value under `outputs` and the consumer must list the job in `needs`.

Question 13Workflow creation

Which pair of keys correctly writes a value to the job output `sha` from within a step?

  1. name on the step plus `echo "sha=$SHA" >> "$GITHUB_OUTPUT"`
  2. id on the step plus `echo "sha=$SHA" >> "$GITHUB_ENV"`
  3. name on the step plus `echo "sha=$SHA" >> "$GITHUB_ENV"`
  4. id on the step plus `echo "sha=$SHA" >> "$GITHUB_OUTPUT"` Correct answer.

Explanation

A step must have an `id` to be addressable, and step outputs are written by appending `name=value` lines to the file named by `GITHUB_OUTPUT`. The job then maps them under `outputs` using `steps.<id>.outputs.<name>`.

Question 14Workflow creation

Which key caches a directory between workflow runs?

  1. cache: true on the job
  2. actions/cache as a step with `path` and `key` inputs Correct answer.
  3. runs-on: cache
  4. strategy: cache

Explanation

Caching is performed by the `actions/cache` action, which takes a `path` to store and a `key` that identifies the cache. Restoring happens when the key matches a previously saved entry.

Question 15Workflow creation

A workflow needs to upload a build artifact so it can be downloaded after the run. Which action and input pair is correct?

  1. actions/checkout with `name` and `path`
  2. actions/download-artifact with `name` and `path`
  3. actions/upload-artifact with `name` and `path` Correct answer.
  4. actions/setup-node with `name` and `path`

Explanation

`actions/upload-artifact` stores files from the runner for later retrieval and requires a `name` for the artifact and a `path` to the files. Its counterpart `actions/download-artifact` retrieves them in a later job or run.

Question 16Workflow creation

Which key supplies environment variables that are available to every step in a job?

  1. variables at the job level
  2. env at the job level Correct answer.
  3. secrets at the job level
  4. with at the job level

Explanation

`env` can be defined at the workflow, job, or step level, and values at the narrower scope override broader ones. Variables declared under a job's `env` are visible to all of that job's steps.

Question 17Workflow creation

A job must run on a self-hosted runner tagged with both `gpu` and `linux`. Which `runs-on` value selects only runners carrying both labels?

  1. runs-on: [self-hosted, gpu, linux] Correct answer.
  2. runs-on: self-hosted || gpu || linux
  3. runs-on: "self-hosted gpu linux"
  4. runs-on: self-hosted,gpu,linux

Explanation

A list value for `runs-on` is treated as a set of labels that must all be present, so the runner must match every entry. The `self-hosted` label is required to target self-hosted runners.

Question 18Workflow creation

Which `permissions` setting grants a job read access to repository contents while denying everything else?

  1. permissions: contents: write
  2. permissions: contents
  3. permissions: contents: read Correct answer.
  4. permissions: read-all

Explanation

When any permission is set explicitly, all unspecified scopes default to `none`, so listing only `contents: read` grants read access to contents and nothing else. This is the recommended least-privilege pattern.

Question 19Workflow creation

Which statement about `GITHUB_TOKEN` is correct?

  1. It is shared across all repositories in the organization.
  2. It is created automatically for each run and its scopes are limited by the `permissions` key. Correct answer.
  3. It must be generated manually and stored as a repository secret.
  4. It grants full administrative access regardless of workflow settings.

Explanation

`GITHUB_TOKEN` is an installation token minted for the duration of the run and revoked afterward. Its effective scopes come from the workflow or job `permissions` block, defaulting to the repository or organization setting.

Question 20Workflow creation

A reusable workflow stored at `.github/workflows/ci.yml` in the same repository should be called from another workflow. Which job-level key is used?

  1. include: ./.github/workflows/ci.yml
  2. call: ./.github/workflows/ci.yml
  3. runs: ./.github/workflows/ci.yml
  4. uses: ./.github/workflows/ci.yml Correct answer.

Explanation

A job that invokes a reusable workflow uses `uses` with a path beginning `./` for a local file or `owner/repo/path@ref` for an external one. The job may also pass `with` inputs and `secrets`.

Question 21Workflow creation

A reusable workflow must accept a required string input named `target`. Which declaration is correct?

  1. on: workflow_call: target: string
  2. jobs: inputs: target: string
  3. on: workflow_call: inputs: target: type: string required: true Correct answer.
  4. on: workflow_dispatch: target: type: string

Explanation

Inputs for a reusable workflow are declared under `on.workflow_call.inputs`, and each input needs a `type` plus optional `required` and `default`. `workflow_dispatch` inputs configure manual runs, not callers.

Question 22Workflow creation

Which option makes a job run on a schedule every day at 06:30 UTC?

  1. on: schedule: '30 6 * * *'
  2. on: schedule: - cron: '30 6 * * *' Correct answer.
  3. on: cron: '30 6 * * *'
  4. on: schedule: - cron: '6 30 * * *'

Explanation

Scheduled runs use POSIX cron syntax under `on.schedule`, and the fields are minute, hour, day of month, month, and day of week. The hour field is 24-hour UTC, so `30 6` means 06:30.

Question 23Workflow creation

A workflow should run only when files under `src/` change on a push to `main`. Which configuration is correct?

  1. on: push: include: ['src/**']
  2. on: push: branches: [main] paths: - 'src/**' Correct answer.
  3. on: push: paths: ['src/**'] branch: main
  4. on: push: branches: [main] files: ['src/**']

Explanation

`push` supports both `branches` and `paths` filters, and a run occurs only when both match. The `paths` filter accepts glob patterns such as `src/**`.

Question 24Workflow creation

Two jobs both write to the same cache key. What happens when the second job tries to save the cache?

  1. The save is skipped because a cache with that key already exists and caches are immutable. Correct answer.
  2. The second job overwrites the stored cache with its own contents.
  3. Both caches are stored and merged on restore.
  4. The second job fails with an error that stops the workflow.

Explanation

A cache entry is immutable once written, so a later save with the same key does not replace it. This is why keys typically include a hash of lockfiles and use `restore-keys` for partial matches.

Question 25Workflow creation

Which expression syntax correctly applies a default when a variable is empty?

  1. ${{ default(inputs.name, 'default') }}
  2. ${{ inputs.name ?? 'default' }}
  3. ${{ inputs.name : 'default' }}
  4. ${{ inputs.name || 'default' }} Correct answer.

Explanation

GitHub Actions expressions support the `||` operator, which returns the right operand when the left is falsy, making it the idiomatic way to supply a fallback. There is no null-coalescing operator and no `default` function.

Question 26Workflow creation

Which top-level workflow key names the workflow as it appears in the Actions tab of the repository?

  1. display
  2. title
  3. label
  4. name Correct answer.

Explanation

The optional top-level `name` key sets the workflow's display name in the Actions UI; if omitted, GitHub shows the workflow file path instead. Keys such as `title`, `label`, and `display` are not part of the workflow syntax and would be rejected as unknown keys.

Question 27Workflow creation

Which key must a workflow file contain at its top level for GitHub to register and execute it?

  1. jobs Correct answer.
  2. tasks
  3. stages
  4. steps

Explanation

A workflow file is only valid when it declares at least one job under the top-level `jobs` key; that map is the container for every job definition. `steps` belongs inside a job, and `stages` and `tasks` are not GitHub Actions workflow keys.

Question 28Workflow creation

Which key inside a job lists the individual commands and actions the job executes in order?

  1. steps Correct answer.
  2. phases
  3. tasks
  4. blocks

Explanation

A job's work is expressed as an ordered list under `steps`, where each entry either uses an action via `uses` or runs a shell command via `run`. The other names are not recognized job keys in GitHub Actions.

Question 29Workflow creation

A step runs a shell command. Which step key supplies that command?

  1. script
  2. cmd
  3. run Correct answer.
  4. exec

Explanation

The `run` key holds inline shell commands executed by the job's shell, and it is mutually exclusive with `uses` within a single step. `script`, `exec`, and `cmd` are not step keys and would make the workflow invalid.

Question 30Workflow creation

Which key in a step references a published action such as `actions/checkout@v4`?

  1. action
  2. run
  3. with
  4. uses Correct answer.

Explanation

The `uses` key names an action by its `owner/repo@ref` reference, optionally with a subdirectory path. `run` is for shell commands, `with` only supplies inputs to an action already named by `uses`, and `action` is not a step key.

Question 31Workflow creation

Which key inside a step passes parameters such as `fetch-depth: 0` to an action?

  1. env
  2. inputs
  3. with Correct answer.
  4. args

Explanation

Action inputs are supplied as a map under the step's `with` key, where each child key matches an input declared by the action. `env` sets environment variables, `args` is a Docker-container argument key rather than a step input map, and `inputs` is used in reusable workflow and action metadata contexts.

Question 32Workflow creation

Which expression references the value of an environment variable named `DEPLOY_ENV` inside a workflow?

  1. ${{ env.DEPLOY_ENV }} Correct answer.
  2. ${{ vars.DEPLOY_ENV }}
  3. ${{ secrets.DEPLOY_ENV }}
  4. ${{ inputs.DEPLOY_ENV }}

Explanation

The `env` context exposes variables defined with the `env` key at workflow, job, or step scope. `vars` reads configuration variables, `secrets` reads encrypted secrets, and `inputs` reads workflow or action inputs, so none of them resolve a plain `env` entry.

Question 33Workflow creation

Which file path is required for GitHub to recognize a workflow definition in a repository?

  1. .github/workflows/deploy.yml Correct answer.
  2. workflows/deploy.yml
  3. .github/workflow/deploy.yml
  4. .github/actions/deploy.yml

Explanation

GitHub only loads workflow files stored directly in `.github/workflows/` at the repository root, and they must be YAML files. Subdirectories under that folder are not scanned, and the singular `.github/workflow/` directory is not recognized.

Question 34Workflow creation

A workflow should start on pushes to `main` and on pull requests targeting `main`. Which `on` configuration expresses this?

  1. on:\n push:\n branches: [main]\n pull_request: [main]
  2. on: [push, pull_request]\n branches: [main]
  3. on:\n push:\n branches: [main]\n pull_request:\n branches: [main] Correct answer.
  4. on:\n push: main\n pull_request: main

Explanation

Each event under `on` is its own mapping, so `push` and `pull_request` each get a `branches` filter listing `main`. Event filters cannot be shared across events, and a bare event name does not accept branch filters.

Question 35Workflow creation

A workflow should be started manually from the Actions UI with a text input named `reason`. Which configuration provides this?

  1. on:\n workflow_dispatch:\n inputs:\n reason:\n type: string Correct answer.
  2. on:\n workflow_call:\n inputs:\n reason:\n type: string
  3. on:\n manual:\n inputs:\n reason:\n type: string
  4. on:\n repository_dispatch:\n inputs:\n reason:\n type: string

Explanation

The `workflow_dispatch` event enables manual runs and accepts an `inputs` map where each input declares a type such as `string`. `repository_dispatch` is triggered by API calls, `workflow_call` is for reusable workflows, and `manual` is not an event name.

Question 36Workflow creation

A job needs to be skipped unless a repository configuration variable named `ENABLE_DEPLOY` equals `true`. Which job-level condition is correct?

  1. if: secrets.ENABLE_DEPLOY == 'true'
  2. if: inputs.ENABLE_DEPLOY == 'true'
  3. if: vars.ENABLE_DEPLOY == 'true' Correct answer.
  4. if: env.ENABLE_DEPLOY == true

Explanation

Configuration variables are read through the `vars` context, and their values are strings, so they are compared to the quoted literal `'true'`. `env` does not automatically expose configuration variables, `secrets` holds encrypted values, and `inputs` only applies to workflows or actions that declare inputs.

Question 37Workflow creation

A step must continue running even when an earlier step in the same job fails. Which step key achieves this?

  1. if: success()
  2. fail-fast: false
  3. if: always() Correct answer.
  4. continue-on-error: true

Explanation

Status check functions in a step's `if` control whether it runs regardless of prior failures, and `always()` returns true in every case. `continue-on-error` marks a failing step as tolerated but does not cause later steps to run, `success()` is the default behavior, and `fail-fast` is a matrix strategy key.

Question 38Workflow creation

A job must run only when the triggering actor is not the `dependabot[bot]` account. Which job-level condition is correct?

  1. if: github.actor != 'dependabot[bot]' Correct answer.
  2. if: github.repository != 'dependabot[bot]'
  3. if: github.triggering_actor == 'dependabot[bot]'
  4. if: github.actor == 'dependabot[bot]'

Explanation

The `github.actor` context holds the account that initiated the run, and comparing it with `!=` excludes the bot. The equality forms would do the opposite, and `github.repository` holds the `owner/name` repository string, not a user account.

Question 39Workflow creation

A job needs to read the commit message of the triggering commit into a step. Which context property provides the commit message?

  1. github.event.head_commit.message Correct answer.
  2. github.sha.message
  3. github.event.message
  4. github.commit.message

Explanation

For push events, the webhook payload is exposed through `github.event`, and the commit message is at `head_commit.message`. `github.sha` is only a SHA string, and the other paths do not exist in the event payload.

Question 40Workflow creation

Which snippet correctly maps a step output named `tag` to a job output named `image_tag`?

  1. outputs:\n image_tag: ${{ job.meta.outputs.tag }}
  2. outputs:\n image_tag: ${{ steps.meta.tag }}
  3. outputs:\n image_tag: ${{ steps.meta.outputs.tag }} Correct answer.
  4. outputs:\n image_tag: ${{ env.meta.tag }}

Explanation

Step outputs are read from the `steps` context using `steps.<step_id>.outputs.<name>`, and job-level `outputs` maps a job output name to that expression. The other forms omit the `outputs` level or reference the wrong context.

Question 41Workflow creation

A workflow defines a job-level `env` entry `NODE_ENV: test` and a step-level `env` entry `NODE_ENV: production`. What does the step see?

  1. `production`, because the step-level value takes precedence Correct answer.
  2. `test`, because job-level values override step-level values
  3. The workflow fails because the variable is defined twice
  4. Both values concatenated as `test,production`

Explanation

Environment variables are resolved with the most specific scope winning, so a step-level `env` overrides a job-level entry of the same name. Redefining a variable at a narrower scope is allowed and does not cause an error.

Question 42Workflow creation

A job sets `timeout-minutes: 10` and one of its steps sets `timeout-minutes: 30`. What is the effective limit for that step?

  1. 10 minutes, because the job timeout caps the whole job Correct answer.
  2. 40 minutes, because the two limits are added
  3. No limit, because conflicting values cancel out
  4. 30 minutes, because the step-level value overrides the job

Explanation

The job's `timeout-minutes` bounds the entire job, so no step can run beyond it even if the step declares a larger value. The step-level timeout can only shorten the effective limit, never extend past the job cap.

Question 43Workflow creation

Which expression correctly references the value of a matrix dimension named `node` for the current job?

  1. ${{ strategy.node }}
  2. ${{ matrix.node }} Correct answer.
  3. ${{ job.matrix.node }}
  4. ${{ matrix[0] }}

Explanation

Values from `strategy.matrix` are exposed in the `matrix` context, so a dimension named `node` is read as `matrix.node`. The `strategy` context holds settings such as `job-index`, and there is no `job.matrix` context.

Question 44Workflow creation

A workflow defines a top-level `defaults.run.shell` value and a job that sets its own `defaults.run.shell`. Which shell does a `run` step in that job use?

  1. The job fails because `defaults` may only appear once
  2. The shell is chosen per step and defaults are ignored
  3. The workflow-level shell, because top-level defaults always win
  4. The job-level shell, because more specific defaults override workflow defaults Correct answer.

Explanation

`defaults` can be set at workflow and job scope, and the job-level setting takes precedence for steps in that job. Steps may still override the shell with their own `shell` key, but absent that, the job default applies.

Question 45Workflow creation

Two jobs, `test` and `package`, both need to run, and `package` must start only after `test` succeeds. Which key belongs on `package`?

  1. after: test
  2. depends: test
  3. requires: test
  4. needs: test Correct answer.

Explanation

The `needs` key lists job IDs that must complete successfully before the job runs, and it also makes their outputs available through the `needs` context. `after`, `depends`, and `requires` are not GitHub Actions job keys.

Question 46Workflow creation

A job declares `needs: [build, test]`, and `build` fails while `test` succeeds. What happens to the dependent job by default?

  1. It is skipped because one required job failed Correct answer.
  2. It runs but ignores the outputs of `build`
  3. It is cancelled before it starts and marked failed
  4. It runs because at least one dependency succeeded

Explanation

By default a job runs only when every job listed in `needs` completes successfully, so a single failed dependency causes the dependent job to be skipped. Adding a status function such as `always()` or `failure()` in the job's `if` changes that behavior.

Question 47Workflow creation

Which snippet passes the variable `target` into a `run` step as an environment variable without embedding it in the shell command text?

  1. env:\n TARGET: inputs.target\nrun: ./deploy.sh
  2. env:\n TARGET: ${{ inputs.target }}\nrun: ./deploy.sh Correct answer.
  3. run: ./deploy.sh\nwith:\n TARGET: ${{ inputs.target }}
  4. run: TARGET=${{ inputs.target }} ./deploy.sh

Explanation

Defining the value under the step's `env` map exposes it to the shell as a normal environment variable, which avoids shell interpolation problems. `with` is only for action inputs, an unquoted `inputs.target` is a literal string, and the inline assignment embeds the value in the command text.

Question 48Workflow creation

A step runs `echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"`. What does this accomplish?

  1. It writes `sha` to the job log only
  2. It sets a step output named `sha` for later steps and jobs to read Correct answer.
  3. It creates an environment variable for subsequent steps
  4. It stores the value as a workflow artifact

Explanation

Appending `name=value` lines to the file referenced by `GITHUB_OUTPUT` publishes step outputs, which are then read via `steps.<id>.outputs.sha`. It does not create environment variables, which require `GITHUB_ENV`, and it does not produce an artifact.

Question 49Workflow creation

Which expression syntax applies a fallback value when `inputs.version` is empty?

  1. ${{ inputs.version || 'latest' }} Correct answer.
  2. ${{ default(inputs.version, 'latest') }}
  3. ${{ inputs.version ?? 'latest' }}
  4. ${{ inputs.version or 'latest' }}

Explanation

GitHub Actions expressions use `||` to return the right-hand operand when the left side is falsy, which covers empty strings and unset inputs. The `??` operator, the word `or`, and a `default()` function are not part of the expression language.

Question 50Workflow creation

A workflow uses `permissions: {}` at the top level and a job sets `permissions: contents: read`. What token access does that job have?

  1. Read access to contents plus write access to packages
  2. Full default permissions because the job map is invalid
  3. No permissions at all because the top-level value is empty
  4. Read-only access to repository contents and nothing else Correct answer.

Explanation

A job-level `permissions` map replaces the workflow-level setting for that job, so listing only `contents: read` grants that single scope. An empty top-level map sets all scopes to none, and the job map narrows or redefines access for that job.