> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerix.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Angular — Source Maps

> Upload your production source maps privately so Lerix shows Angular errors at the original file and line.

## Introduction

Production Angular builds are minified, so a stack trace from a real user
looks like this:

```text theme={"dark"}
onConnMessage@https://app.example.com/chunk-Cr8GYWvZ.js:10:14780
```

When you upload your build's source maps to Lerix, the dashboard maps each
frame back to your original code, for example `src/app/chat/chat.page.ts:142`,
and shows the surrounding lines.

The maps are uploaded privately and deleted from your build output before you
deploy. They are never served publicly, so your source code stays private.

<Note>
  Complete the [Angular installation](/frameworks/angular/installation) first.
  Setting a release requires `@lerix-dev/lerix-core` 1.1.0 or newer.
</Note>

## 1. Enable hidden source maps

In `angular.json`, turn on source maps for the production configuration under
`projects.<your-app>.architect.build.configurations.production`:

```json angular.json theme={"dark"}
"production": {
  "sourceMap": {
    "scripts": true,
    "styles": false,
    "hidden": true,
    "vendor": false
  }
}
```

`"hidden": true` generates the `.map` files without adding a
`//# sourceMappingURL` comment to the shipped JavaScript, so browsers never
try to load them.

Run `ng build` and check that `.js.map` files appear next to the bundles. The
output folder is usually `dist/<your-app>/browser`.

## 2. Create a private API key

Uploading source maps needs a private key, separate from the public project
key your app uses.

1. Open your project in the [Lerix Dashboard](https://app.lerix.dev).
2. Go to **Project settings** → **API keys**.
3. Create a key with the **Upload source maps** permission (or **Full access**).

<Warning>
  This key is secret. Store it as a CI secret and never put it in client code
  or commit it to your repository.
</Warning>

## 3. Upload the maps after each build

After `ng build` and before you deploy, run the Lerix CLI on the build output:

```bash theme={"dark"}
npx @lerix-dev/lerix-cli upload
```

Run it from your project folder. It finds the build output on its own
(`angular.json` (`outputPath`)) and uses the `version` from `package.json` as the release. To set
them yourself: `npx @lerix-dev/lerix-cli upload dist/my-app/browser --release 1.4.0`.

The CLI uploads every `*.js.map` file in the folder (it skips `node_modules`
and CSS maps), then deletes the `.map` files from the build output so they are
never deployed. If any upload fails, it keeps the maps and exits with code 1,
so you can retry the step. The CLI requires Node.js 18.17 or newer.

### Upload on every build

Instead of running the command yourself, install the CLI in your project and
let npm run it after each build:

```bash theme={"dark"}
npm install --save-dev @lerix-dev/lerix-cli
```

```json package.json theme={"dark"}
"scripts": {
  "build": "ng build",
  "postbuild": "lerix upload --optional"
}
```

Now every `npm run build` uploads the maps. `--optional` keeps local builds
working: on a machine without `LERIX_SECRET_KEY` (a developer's laptop), the
upload is skipped instead of failing the build, and the `.map` files are still
deleted. Set the keys in your CI or build server, where the release build runs.

<Note>
  pnpm and Yarn 2+ don't run `postbuild` scripts. Chain the command instead:
  `"build": "ng build && lerix upload --optional"`.
</Note>

### Options

Each option can also be set with an environment variable.

| Option | Environment variable | Description |
| - | - | - |
| `--release` | `LERIX_RELEASE` | The version this build ships as. Defaults to `version` in `package.json`. Pass the same value to the SDK (see step 4) |
| `--api-key` | `LERIX_API_KEY` | Your normal public project API key |
| `--project-id` | `LERIX_PROJECT_ID` | Your project ID |
| `--secret-key` | `LERIX_SECRET_KEY` | The private key from step 2 |
| `--url` | `LERIX_URL` | Lerix API URL. Defaults to `https://api.lerix.dev/v1` |
| `--keep-maps` | | Keep the `.map` files in the build output instead of deleting them |
| `--dry-run` | | List the maps that would be uploaded, without uploading anything |
| `--optional` | | Skip the upload instead of failing when the keys aren't set (local builds). The `.map` files are still deleted |

## 4. Pass the same release to the SDK

Set `release` in `provideLerix()` to the value you passed to `--release`:

```ts app.config.ts theme={"dark"}
import { ApplicationConfig } from '@angular/core';
import { provideLerix } from '@lerix-dev/lerix-angular';

export const appConfig: ApplicationConfig = {
  providers: [
    provideLerix({
      apiKey: 'your-api-key',
      projectId: 'your-project-id',
      release: '1.4.0',
    }),
  ],
};
```

Lerix matches maps by the script's file name. Angular's chunk names are
content-hashed, so they are unique per build, and Lerix prefers maps from the
same release. Matching still works if you omit `release`, but setting it is
recommended. The release also replaces the `0.0.0` app version previously
shown for web apps.

<Tip>
  Use the same value in both places without editing it by hand: your git
  commit SHA or the `version` from `package.json` both work well.
</Tip>

## Example: GitHub Actions

This workflow builds the app, uploads the maps, then deploys. Add
`LERIX_API_KEY`, `LERIX_PROJECT_ID` and `LERIX_SECRET_KEY` as repository
secrets.

```yaml .github/workflows/deploy.yml theme={"dark"}
jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      LERIX_RELEASE: ${{ github.sha }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci

      # Make the same release available to the app at build time
      - run: echo "export const release = '$LERIX_RELEASE';" > src/environments/release.ts

      - run: npx ng build

      - run: npx @lerix-dev/lerix-cli upload
        env:
          LERIX_API_KEY: ${{ secrets.LERIX_API_KEY }}
          LERIX_PROJECT_ID: ${{ secrets.LERIX_PROJECT_ID }}
          LERIX_SECRET_KEY: ${{ secrets.LERIX_SECRET_KEY }}

      # Deploy dist/my-app/browser here. It no longer contains .map files.
```

Then import the generated value in your config:

```ts app.config.ts theme={"dark"}
import { release } from '../environments/release';

provideLerix({ apiKey: 'your-api-key', projectId: 'your-project-id', release })
```

## What you see in the dashboard

New errors show the original file, line and function, with the surrounding
code. Click **Show minified** to see the stack exactly as the browser sent it.
The AI assistant, GitHub issues and the MCP server all receive the readable
stack too.

* Only errors reported after the maps are uploaded are mapped. Earlier errors
  keep their minified stack.
* Lerix keeps the newest 5,000 maps per project.
* Each map can be up to 50 MB.

## Troubleshooting

| Problem | Fix |
| - | - |
| `no .js.map files found` | Source maps are not enabled for the production build. Check the `sourceMap` setting in step 1 and that you point the CLI at the right output folder. |
| `Uploading source maps needs a private API key...` (`SOURCE_MAP_SECRET_KEY_MISSING`) | `--secret-key` is missing or invalid. Create a private key as described in step 2. |
| `PROJECT_API_KEY_DONT_HAVE_PERMISSION` | The private key lacks the **Upload source maps** permission. Edit the key or create a new one with that permission. |
| The stack is still minified | Check that the SDK `release` matches `--release`, that you uploaded maps from this exact build, and that the error is new. Every rebuild changes chunk hashes, so upload the maps again after each build. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.