---
title: Upgrading and migration
order: 7
description: How to upgrade BxLens safely: what to save first, the steps, the settings that moved or changed order, what a Free server must check, how to verify the result and how to roll back.
icon: lucide:arrow-up-circle
---

# Upgrading and migration

BxLens is a BoxLang module. An upgrade is: save the files, install the new module, restart, check. This page lists what changed since `1.0.0` that can surprise an operator, and how to go back. The full list of changes is in `changelog.md` of the module, under the version you install.

## Before you upgrade

1. **Read the changelog** of the version you install, from the `[Unreleased]` or the version heading down to your current version.
2. **Save the files** in [Backup, retention and disk usage](backup-and-retention.md), at least `boxlang.json`, `config/bxlens-*` and the secrets folder with its key. If you use alerts, also keep `notifications.json` from the store folder: the notification settings live only there.
3. **Keep a console password in `boxlang.json`** (an environment variable or a `bxsecret:` value). A password set in the console lives in the Secret Store and an older build does not read it. A password in `boxlang.json` works in every build, so it is also your way back in, see [Lockout recovery](../security.md#where-the-console-passwords-come-from).
4. **Look at the table below** and at [Moving from older settings](../configuration.md#moving-from-older-settings) for the settings you use.

## The steps

1. Install the new module on the server, for example `install-bx-module bx-lens` or `box install bx-lens`, the same way you installed it. BoxLang 1.19 or newer and Java 21 are required.
2. Restart the runtime. The module reads its settings at start.
3. Check the log for `bx-lens <version> active: bar=..., console=..., collect=...` and for warnings that start with `bx-lens`.
4. Open the console and check, in this order:
   - The login page (or the Register page on Free, see below) loads, and you can sign in.
   - **Settings, Security**: each password says where it comes from (*set in console* or *set in boxlang.json*).
   - **Settings, Storage** (BoxLang+): *State: saving*, no *Last error*, and the Secrets card says *This server can open them: yes*.
   - **Settings, Notifications** (BoxLang+): your recipients, rules and channels are there. Press **Send test mail**.
   - The header shows your license state.
5. With several servers that share a store folder, upgrade them **one after the other** and check each one before the next. A newer build skips an alert rule it does not know from another server's copy instead of discarding the copy, and older error files are still read. We have not tested every pair of builds working side by side, so do not leave servers on different builds for long.

## What changed and what to do

| Area | Before | Now | What to do |
|---|---|---|---|
| Console passwords | Only `console.password` and `console.viewerPassword` in `boxlang.json` | An admin can set both in Settings, Security. A password set there is a salted slow hash in the Secret Store and **wins** over `boxlang.json`. Reset to boxlang.json removes it | Nothing, if `boxlang.json` already has a password. See [Precedence](../configuration.md#precedence-of-the-console-passwords) |
| No password | Not listed in the changelog | The "Set a password first" page has three tabs, and **every other route answers 503** (sign in, registration, API, live stream) until a password exists. It also shows before the registration form | A server that runs with an empty or undecryptable password shows only that page. Set the password, then reload |
| AI key | The variable named in `ai.apiKeyEnv` won over `ai.apiKey` | The order is: key set in the console, then `ai.apiKey`, then `ai.apiKeyEnv` | A server that has both now uses `ai.apiKey` first. Remove the one you do not want |
| SMTP password | No rule for the name of the variable | A password set in the console (write only, BoxLang+), then `notifications.smtp.password`, then the variable named in Settings, Notifications. That name **must start with `LENS_SMTP_`**. A change of the SMTP host asks for a confirmation when a password is set | Rename the variable to `LENS_SMTP_...` and update the name in Settings |
| Store limits | `store.retentionDays`, `maxMB` and `staleAfterHours` could be changed in the console | `boxlang.json` only. The Storage tab shows them read only. A saved override of them is ignored | Set them in `boxlang.json` and restart |
| Store layout | `store.retentionHours`, one file limited by `store.maxMB` (50), `errors.json` and `reports.json` directly in `store.dir` | `store.retentionDays` (an old `retentionHours` still counts, rounded up to days). `store.maxMB` limits the whole folder, default 500. The two files move into this server's subfolder at the first start | Check the cap against your fleet: the fair share is `maxMB` divided by the number of servers |
| Secret Store | none | `config/bxlens-secrets` (or `secrets.dir`) with `secrets.key` and `secrets.json`, free | Back up the folder. On several servers, share it and the key. See [Several servers](multi-server.md) |
| Read only mode | Refused changes in general | Lets through only the routes named in the code: heap dumps, the datasource connection test, the AI calls and the chat with Lensy | Nothing. A new change route is refused until it is listed |
| Viewer | Not listed in the changelog | Logs, Environment, System and Threads are admin only, a few setting values are hidden, and a viewer cannot approve an action of Lensy | Tell viewers |
| `console.allowHeapDump` | Read with a default, not declared | Declared in the schema, default `false` | Nothing |
| Registration | none | The console on **Free and Trial** needs a one time, free registration per server. BoxLang+ needs none. The bar needs none | See below |
| Data functions | `lensReport`, `lensErrors`, `lensQueries` and `lensInflight` returned data | On Free they return nothing (`locked: true` or an empty array) | Check scripts on Free servers that call them |
| Content-Security-Policy | Described as strict | The documentation now says what it allows (`unsafe-eval` for scripts, `unsafe-inline` for styles). Nothing about the policy changed | Nothing |
| Mail in the health snapshot | The whole Mail page of a server | The numbers, servers, the counts of the queue and settings only. No message is in it: not the list of sent messages, and not the messages waiting in the spool (sender, recipients, subject and error stay on their server) | Nothing to do |
| bx-ai | 3.4.0 | A newer 3.6.0 snapshot, bundled in `modules/bxai` | Nothing to install. Lensy reaches only HTTP(S) MCP servers, as before |

### A Free server

If you upgrade a server on **Free** from `1.0.0`:

1. The first time you open the console it shows the **Register** page, before the sign in. See [Register](../console/register.md). Registering is free and starts a 14 day trial of the BoxLang+ features.
2. The server needs outgoing HTTPS to the registration service once, from the server. An air gapped server cannot register. Use BoxLang+.
3. In a container, set `LENS_SERVER_NAME` to a fixed name and give the key with `registration.keyEnv`, so every deploy has the same name and key.
4. After the trial the BoxLang+ features stop at the next license check and the server stays free and registered.

## Rollback

1. Stop BoxLang.
2. Install the previous module version.
3. Put back the saved `boxlang.json`, the `config/bxlens-*` files and the secrets folder if you changed them.
4. Start BoxLang and run the checks above.

What to expect:

- **Passwords.** A password set in the console is ignored by a build that does not have the Secret Store. That is why `boxlang.json` should hold one. If it does not, the older build shows its setup page.
- **Files the newer build wrote** (the store subfolders, `secrets.json`, the notification state) stay where they are. They are JSON and plain files. An older build that does not use them leaves them alone. We have not tested running an older build over data a newer one wrote, so keep the backup, and take the store folder out of the way (`store.dir`) if an older build misbehaves with it.
- **Settings.** A saved override with a key the older build does not know is skipped when the file is read, and a warning is logged.
- **Registration.** A build from before the registration feature does not ask for it. The key file `config/bxlens-registration.json` stays where it is.
- **Secrets.** The sealed secrets stay closed to a build without the Secret Store. Enter the SMTP password and the AI key in `boxlang.json` again if you go back to such a build.

## When something looks wrong after an upgrade

See [Troubleshooting](../troubleshooting.md): the setup page, a locked out admin, a 403 in the console, secrets that cannot be opened, a store that saves nothing, and notifications that are not sent.
