# Where Is the Main Entry Point for actions/checkout? Understanding the Execution Flow

> Discover the main entry point for actions/checkout execution. Learn how src/main.ts compiles to dist/index.js and is declared in action.yml for Node.js runtime.

- Repository: [GitHub Actions/checkout](https://github.com/actions/checkout)
- Tags: internals
- Published: 2026-08-29

---

**The main entry point for `actions/checkout` is [`src/main.ts`](https://github.com/actions/checkout/blob/main/src/main.ts), which compiles to [`dist/index.js`](https://github.com/actions/checkout/blob/main/dist/index.js) and is declared in [`action.yml`](https://github.com/actions/checkout/blob/main/action.yml) as the executable run by the Node.js runtime.**

When you use `actions/checkout@v4` in a workflow, GitHub Actions needs to know exactly which file to execute. While the metadata declaration lives in the repository root, the actual orchestration logic resides in a specific TypeScript file that handles both repository cloning and cleanup operations.

## How the Entry Point Is Defined in action.yml

The [`action.yml`](https://github.com/actions/checkout/blob/main/action.yml) file serves as the action manifest, telling the GitHub Actions runner which runtime to use and which file to load. According to the `actions/checkout` source code, the metadata specifies:

```yaml
runs:
  using: node24            # Node.js runtime version

  main: dist/index.js      # Executed during the main step

  post: dist/index.js      # Executed during the post step

```

This configuration instructs the runner to execute [`dist/index.js`](https://github.com/actions/checkout/blob/main/dist/index.js) twice—once during the main job phase to clone the repository, and once during the post phase to clean up temporary resources. The compiled bundle in [`dist/index.js`](https://github.com/actions/checkout/blob/main/dist/index.js) originates from the TypeScript source file **[`src/main.ts`](https://github.com/actions/checkout/blob/main/src/main.ts)**.

## src/main.ts: The True Entry Point Logic

The file **[`src/main.ts`](https://github.com/actions/checkout/blob/main/src/main.ts)** contains the primary execution logic that determines whether to clone the repository or perform cleanup tasks. The action uses a conditional check based on **`stateHelper.IsPost`** to determine which phase is running:

```typescript
// src/main.ts
async function run(): Promise<void> {
  const sourceSettings = await inputHelper.getInputs()
  core.info(`::add-matcher::${path.join(__dirname, 'problem-matcher.json')}`)
  await gitSourceProvider.getSource(sourceSettings)
  core.setOutput('ref', sourceSettings.ref)
}

async function cleanup(): Promise<void> {
  await gitSourceProvider.cleanup(stateHelper.RepositoryPath)
}

if (!stateHelper.IsPost) { 
  run() 
} else { 
  cleanup() 
}

```

This architecture allows a single compiled file to handle both the setup and teardown phases of the checkout process.

## The Execution Flow: Pre-Run vs Post-Run

The `actions/checkout` entry point bifurcates its behavior based on the workflow phase, ensuring resources are properly managed throughout the job lifecycle.

### Pre-Run Phase: Cloning and Setup

When `stateHelper.IsPost` is false, the **`run()`** function executes to clone the repository:

1. **`inputHelper.getInputs()`** retrieves and validates all inputs specified in the workflow YAML (such as `fetch-depth` and `token`)
2. A problem matcher is registered to provide enhanced error reporting for git operations
3. **`gitSourceProvider.getSource(sourceSettings)`** performs the actual git clone, fetch, and checkout operations
4. **`core.setOutput('ref', sourceSettings.ref)`** exposes the resolved reference as a step output for downstream use

### Post-Run Phase: Cleanup

When the job completes, the runner invokes the same [`dist/index.js`](https://github.com/actions/checkout/blob/main/dist/index.js) file again, but this time `stateHelper.IsPost` is true, triggering the **`cleanup()`** function. This phase removes sensitive temporary resources such as the Personal Access Token (PAT) or SSH private keys from the filesystem, ensuring no credentials persist after the job finishes.

## Practical Workflow Examples

### Basic Repository Checkout

Here is a minimal workflow demonstrating how the entry point is triggered:

```yaml
name: CI
on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4   # Triggers src/main.ts logic

        with:
          fetch-depth: 0

      - name: Show checked-out commit
        run: echo "Checked out ${{ steps.checkout.outputs.ref }}"

```

### Accessing the ref Output

You can capture the resolved reference that [`src/main.ts`](https://github.com/actions/checkout/blob/main/src/main.ts) exposes via `core.setOutput`:

```yaml
- name: Checkout
  id: checkout
  uses: actions/checkout@v4

- name: Use the ref
  run: |
    echo "The action checked out ref: ${{ steps.checkout.outputs.ref }}"

```

The post-step cleanup runs automatically when the job completes—no additional YAML configuration is required to trigger the cleanup logic defined in [`src/main.ts`](https://github.com/actions/checkout/blob/main/src/main.ts).

## Summary

- **[`action.yml`](https://github.com/actions/checkout/blob/main/action.yml)** points to [`dist/index.js`](https://github.com/actions/checkout/blob/main/dist/index.js) as the executable entry point for both main and post phases
- **[`src/main.ts`](https://github.com/actions/checkout/blob/main/src/main.ts)** is the TypeScript source file that implements the core logic, checking `stateHelper.IsPost` to determine execution mode
- The **pre-run** phase (`run()`) handles input parsing, git operations via `gitSourceProvider.getSource`, and output exposure
- The **post-run** phase (`cleanup()`) removes temporary credentials and resources via `gitSourceProvider.cleanup`
- The compiled [`dist/index.js`](https://github.com/actions/checkout/blob/main/dist/index.js) bundle is what the Node.js runtime actually executes in the GitHub Actions runner

## Frequently Asked Questions

### What file does GitHub Actions actually execute?

The runner executes **[`dist/index.js`](https://github.com/actions/checkout/blob/main/dist/index.js)**, which is the compiled and bundled version of the TypeScript source. According to the [`action.yml`](https://github.com/actions/checkout/blob/main/action.yml) configuration, this file runs during both the main step (to clone the repository) and the post step (to clean up resources).

### How does actions/checkout know whether to run or cleanup?

The action checks the **`stateHelper.IsPost`** boolean flag. If this flag is false, the entry point calls the **`run()`** function to perform the checkout. If true, it calls the **`cleanup()`** function to remove temporary files and credentials. This state is persisted between the main and post phases by the GitHub Actions runner.

### Can I modify the entry point behavior?

You can fork the `actions/checkout` repository and modify **[`src/main.ts`](https://github.com/actions/checkout/blob/main/src/main.ts)** to change the execution logic. After making changes, you must rebuild the distribution bundle using `npm run build` or `npm run pack` to regenerate [`dist/index.js`](https://github.com/actions/checkout/blob/main/dist/index.js), as the runner always executes the compiled bundle rather than the raw TypeScript source.

### Where is the compiled JavaScript located?

The compiled entry point resides at **[`dist/index.js`](https://github.com/actions/checkout/blob/main/dist/index.js)** in the repository root. This file is generated from [`src/main.ts`](https://github.com/actions/checkout/blob/main/src/main.ts) and includes all dependencies bundled together, allowing the action to run without requiring `npm install` in the workflow environment.