# What is the difference between static and dynamic analysis?

Static analysis examines code without running it, while dynamic analysis observes the program as it runs, so each finds bugs that the other misses.

Last updated September 29, 2026, 8 min read

## Learning objectives

After reading this article you will be able to:

-   Define static and dynamic analysis
-   Explain where each runs in a pipeline
-   Compare the defect classes each finds

## Related content

-   [What is code review?](https://specstory.com/learning/code-review/code-review)
-   [What is AI code review?](https://specstory.com/learning/code-review/ai-code-review)
-   [How to review a pull request written by a coding agent](https://specstory.com/learning/code-review/reviewing-agent-pull-requests)

## What is the difference between static and dynamic analysis?

[Static analysis](https://specstory.com/learning/code-review/static-analysis) checks a program by reading its source code without running it, and dynamic analysis checks it by observing the program while it runs. Static analysis finds problems visible in the code, e.g. a value of the wrong type. Dynamic analysis finds problems that appear only when the code runs.

Each method misses bugs that the other finds, so neither one alone shows that a change works. Teams usually run both in one pipeline. The terms are also written as static code analysis and dynamic code analysis.

[Code review](https://specstory.com/learning/code-review/code-review) is a static check too, because the reviewer is [reading code](https://specstory.com/learning/verification/reading-vs-running-code), not running it. In security work, the same split is called static application security testing ([SAST](https://specstory.com/learning/glossary#sast)) and dynamic application security testing ([DAST](https://specstory.com/learning/glossary#dast)).

## What is static analysis?

The International Software Testing Qualifications Board (ISTQB) [defines static analysis](https://glossary.istqb.org/en_US/term/static-analysis) as the automated evaluation of a component or system without executing it. A tool parses the code into a structure, e.g. a syntax tree, checks it against rules, and reports each finding with a file and a line.

Static analysis takes three common forms:

-   **Linting.** Tools for [linting](https://specstory.com/learning/code-review/linting) compare code with style and correctness rules, e.g. a variable that is declared and never used.
-   **Type checking.** A [type checking](https://specstory.com/learning/glossary#type-checking) tool confirms that each value matches its declared type, e.g. no string where a number is expected.
-   **Data flow analysis.** The tool traces how a value moves through the code, e.g. from a form field into a database query.

Because nothing runs, static analysis needs no test environment or test data, and it can flag code on paths that no test reaches. It has no access to runtime values, e.g. what a database returns, so the tools estimate which values are possible.

## What is dynamic analysis?

Dynamic analysis is a method that observes a program while it runs, to find bugs that appear only at runtime. ISTQB [defines dynamic analysis](https://glossary.istqb.org/en_US/term/dynamic-analysis) as evaluating a component or system based on its behavior during execution.

Dynamic analysis takes four common forms:

-   **Testing.** A test runs the code with chosen input and compares the result with an expected value. [End-to-end testing](https://specstory.com/learning/testing/end-to-end-testing) does this for a whole workflow.
-   **Fuzzing.** [Fuzzing](https://specstory.com/learning/test-quality/fuzzing) feeds a program large numbers of random or malformed inputs and records crashes and hangs.
-   **Instrumented runs.** A tool builds extra checks into the program, and the checks run with it, e.g. Go's race detector (`go test -race`). It reports a data race, one kind of [race condition](https://specstory.com/learning/debugging/race-condition), only when the run triggers it.
-   **Runtime monitoring.** [Runtime verification](https://specstory.com/learning/verification/runtime-verification) checks a running system against stated properties, e.g. that an order total is never negative.

A [hydration error](https://specstory.com/learning/cli-and-web/hydration-error), where the browser's JavaScript renders different HTML from the server's, is one bug that only a run shows.

## When should a team use static or dynamic analysis?

Here is an illustrative example. Acme Co. sells furniture online. A developer asks a [coding agent](https://specstory.com/learning/ai-coding/coding-agent) to "Let customers edit their delivery address during checkout." The change goes through both kinds of check:

1.  The agent edits the checkout code, and the type checker reports `Type 'string | undefined' is not assignable to type 'string'.`
2.  The agent handles the missing value by starting a fresh checkout session. The type checker and the linter exit with code 0.
3.  A reviewer reads the diff and approves it.
4.  A test runner opens the store in a browser, adds 2 items to the cart, starts checkout, and changes the address.
5.  The run compares the cart with the 2 items it added. The address saved, but the cart emptied.
6.  The run records the steps. A developer replays them and finds the cause, a fresh checkout session that has no cart.

Static analysis caught the type error before anything ran. Only the run found the empty cart, because the changed code was well typed.

Static checks suit each save and commit, because they are fast and name a line. A run suits each change that alters what a user can do. This example is simplified. A real project would also run unit tests and a security scan on each pull request.

## What changes when a coding agent writes the code?

A coding agent often runs the type checker and the linter inside its loop. The agent edits the code until both exit cleanly. That makes the static checks a target, and a target can be met without fixing the cause. An agent can add a suppression comment, e.g. `// @ts-ignore`, and the error goes away while the defect stays.

[AI code review](https://specstory.com/learning/code-review/ai-code-review) that reads a diff is static analysis too, even when it uses logs from the deployed code.

A lint rule can reject suppression comments, e.g. `@typescript-eslint/ban-ts-comment`, so a suppressed type error still fails the lint step. A cast to `any` turns off type checks for one value, so a reviewer can treat each one in an agent's diff as a finding.

## How are SAST and DAST related?

SAST and DAST are the security forms of static and dynamic analysis. SAST scans source code for vulnerability patterns without running it, e.g. user input that reaches a database query unescaped. DAST sends crafted requests to a running application from outside and checks the responses, with no access to the source.

SAST can point to the exact line but reports some false positives, because it cannot check what happens at runtime, e.g. whether a flagged path ever runs. DAST finds flaws that depend on deployment, e.g. a missing security header, but cannot name the line that caused them.

Both are security testing, not functional testing. Neither checks that a feature does what was asked, e.g. that changing an address keeps the cart intact.

## Can static and dynamic analysis be used together?

Static and dynamic analysis are usually used together, in the order that a change moves through a continuous integration and delivery ([CI/CD](https://specstory.com/learning/ci-cd/ci-cd)) pipeline. Static checks come first because they are fast and need nothing running. Dynamic checks come later because they need the software running with test data.

Diagram: Where static and dynamic analysis usually run

Static checks sit early in the pipeline, and dynamic checks usually begin in CI. CI is the one stage in this diagram that runs both.

The [Secure Software Development Framework](https://csrc.nist.gov/pubs/sp/800/218/final) from the National Institute of Standards and Technology (NIST) treats reviewing code (PW.7) and testing executable code (PW.8) as separate practices. Using both methods still leaves gaps:

-   **Static tools approximate.** They report some false positives and miss bugs that depend on runtime values.
-   **A run checks only what it reaches.** No findings is not the same as complete coverage.
-   **Some dynamic checks cost more.** End-to-end runs and DAST need a running copy close to production, so teams run them less often.

## How do static and dynamic analysis compare?

The two methods differ on these points:

| Point | Static analysis | Dynamic analysis |
| --- | --- | --- |
| What it examines | Source code and configuration files | The program's behavior while it runs |
| Where it usually runs | Editor, pre-commit hook, and CI | Local test runs, CI, staging, and production monitoring |
| False alarms | Some findings are false positives | A reported failure happened, at least on that run |
| Paths it covers | Includes paths that no test runs | Only the paths that the run reaches |
| Type errors and unsafe patterns | Finds them before anything runs | Finds them only if a run triggers a failure |
| Races and timing bugs | Flags risky patterns, not the failure | Finds them when the run triggers one |
| Wrong output and broken workflows | Misses them unless a rule describes them | Finds them when a check compares results |

## What does running the program add to static checks?

Running the program adds a record of what the software did during a workflow. After static checks pass, run the workflow that the change touched and keep the steps, so a failure can be repeated.

RunStory runs your software in a separate environment, tries relevant workflows, and checks the results. It sends reproducible failures to your coding agent and verifies the fix. It is in private alpha for CLIs and web apps.

[Join the RunStory alpha →](https://specstory.com/runstory#alpha)

## FAQs

### Is a type checker a form of static analysis?

A type checker is a form of static analysis, because it checks that values match their declared types without running the program. A type checker cannot check what well typed code does with real data.

### Is testing a form of dynamic analysis?

Testing that runs the program is a form of dynamic analysis, because each test compares the result with an expected one. Dynamic analysis also includes runs with no expected output, e.g. fuzzing, which records crashes and hangs.

### What is the difference between SAST and DAST?

SAST scans source code for security flaws without running it, while DAST sends requests to a running application from outside and checks the responses. SAST usually runs in CI on each change, and DAST runs later against a deployed copy, e.g. a staging environment.

### Does dynamic analysis need the source code?

Dynamic analysis does not always need the source code. DAST sends crafted requests to a running application from outside and checks the responses, with no access to the source.

---

Source: [Static vs. dynamic analysis | SAST vs. DAST | SpecStory](https://specstory.com/learning/code-review/static-vs-dynamic-analysis)
