# l4 estimate

> Estimate the monthly cost of Terraform and CloudFormation before resources are created.

Source: https://docs.levelfour.ai/cli/commands/estimate


`l4 estimate` prices the Terraform and CloudFormation in your workspace and estimates the monthly cost of the resources they define. It needs no `terraform plan` and no deployed stack. Point it at directories, individual files, or a mix. It reads a directory recursively.

```bash
l4 estimate
l4 estimate ./infra/
l4 estimate main.tf variables.tf
l4 estimate template.yaml --parameter Env=prod
```

Each Terraform root module is priced once, with the modules it calls. Each CloudFormation template is priced with the nested stack templates, `AWS::Include` snippets and `samconfig` files it uses. [CloudFormation](#cloudformation) covers what leaves your machine.

## Flags

| Flag                       | Description                                                                                                                                                                         |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--region <r>`             | AWS region for pricing. Order: `--region`, then `region_override` in `.levelfour/config.yml`, then the template's `samconfig` (for Terraform, its provider block), then `us-east-1` |
| `--gcp-region <r>`         | GCP region (default: auto-detect or `us-central1`)                                                                                                                                  |
| `--azure-region <r>`       | Azure region (default: auto-detect or `eastus`)                                                                                                                                     |
| `--var <key=value>`        | Terraform variable (repeatable)                                                                                                                                                     |
| `--var-file <path>`        | Terraform variable file (repeatable)                                                                                                                                                |
| `--download-modules`       | Download remote modules for accurate estimates (default `true`)                                                                                                                     |
| `--parameter <Key=Value>`  | CloudFormation parameter value, given to every root template that declares `Key` (repeatable). A nested stack gets the parameters its parent passes                                 |
| `--parameters-file <path>` | CloudFormation parameters file for the root templates, in the AWS CLI JSON format or the CodePipeline format                                                                        |
| `--config-env <env>`       | The `samconfig` environment whose parameters and region apply (default `default`)                                                                                                   |
| `--out-file <path>`        | Save the Terraform resource snapshot for later use with `l4 diff`                                                                                                                   |
| `--fail-above <amount>`    | Exit code `2` if monthly cost exceeds this threshold                                                                                                                                |
| `--format`                 | `table`, `json`, or `github-comment` (default `table`)                                                                                                                              |

> **Warning**
>
> Pricing is regional. When no flag, config, provider block or `samconfig` names a region, every AWS resource is priced in `us-east-1`, which returns a plausible total that is wrong for any other region.

Global flags apply, including `--quiet` and `--token`. See [CLI overview](/cli#global-flags).

## CloudFormation

`l4 estimate` reads YAML, JSON and SAM templates. It tells a template apart from other YAML and JSON by its content, so a Kubernetes manifest or a `package.json` in the same directory is left alone.

The CLI parses Terraform on your machine and sends only the resources to the API. **CloudFormation templates are uploaded to the LevelFour API**, which evaluates their parameters, conditions, intrinsic functions and nested stacks, then prices them. The upload holds:

* the templates the CLI found
* the nested stack templates and `AWS::Include` snippets they reference
* the `samconfig` beside each template
* the `--parameters-file`

Nothing outside the git repository goes up. Outside a repository, nothing outside the directory you point at goes up. A file a template references is uploaded only when git tracks it and it is not hidden, vendored or a package manifest, so an ignored `credentials.json` or a `.env.json` stays on your machine. The CLI never follows a symlink to a file it uploads. Before the request goes out, it lists every file it uploads on stderr.

A parameter of a root template takes the first value it finds: `--parameter`, then `--parameters-file`, then the `samconfig` environment `--config-env` names, then the template's `Default`. A nested stack takes the parameters its parent passes down, and its own `Default` for the rest. When the estimate rests on an assumption, such as a parameter priced at its default or a condition LevelFour could not settle, the output lists it under **Assumptions**.

### AWS CDK

The CLI does not run `cdk synth`. Run it yourself, then name each synthesized template:

```bash
cdk synth
l4 estimate cdk.out/MyStack.template.json
```

A directory walk skips `cdk.out`, so name the templates as files.

[Pull request bot](/integrations/pull-request-bot#how-it-prices-a-cloudformation-template) lists the rest of what LevelFour cannot price in a template.

## CI guardrail pattern

Fail the build when the estimated monthly cost is above $500:

```bash
l4 estimate --fail-above 500 -q ./infra/
```

> **Success**
>
> A wired gate exits `2` once the estimate goes over the threshold. That is the guardrail firing rather than the command breaking, and the two carry different codes, so a job can branch on the difference. [Exit codes](/cli#exit-codes) has the full set.

`--fail-above` gates on the total here, so a workspace that sits above the line fails every build, whether or not the change moved it. [`l4 diff`](/cli/commands/diff) gates on the delta instead.

## Saving a snapshot for later comparison

Outside a git repo, save the current Terraform estimate as a baseline you can diff against later:

```bash
l4 estimate --out-file baseline.json ./infra/
# ... make changes ...
l4 diff baseline.json ./infra/
```

In a git repo you need no snapshot at all. See [`l4 diff`](/cli/commands/diff) for the default baseline.

## Posting to a pull request

The `github-comment` format is what the LevelFour GitHub Action uses. Post it by hand with:

```bash
l4 estimate --format github-comment ./infra/ \
  | gh pr comment "$PR_NUMBER" --body-file -
```

## Related

* [`l4 diff`](/cli/commands/diff) compares an estimate against a branch or a saved baseline
* [CI/CD integration](/guides/ci-cd) has the GitHub Actions and GitLab CI jobs that run this command
* [Output formats](/cli/output-formats) covers the global `--json`, `--jq`, `--template` and `--quiet` flags
