App names
The names in .env.local, what each one is for, where its value comes from, and what stops working without it.
These seven are read by the Next.js process. They belong in .env.local on whichever machine runs the app, so
a laptop and a server have their own copy of this half.
Prop
Type
NEXT_PUBLIC_CONVEX_URL
The single required name. It is the address of the Convex deployment the app talks to, and without it the app starts and serves nothing useful.
Where it comes from. npx convex dev prints it when it starts, and the Convex dashboard shows it under
the project's settings. It looks like https://quick-fox-1234.convex.cloud.
What breaks without it. Everything. This is the one gate: the app's authentication helper throws by name rather than letting a page fail somewhere unrelated.
It is a public value, and that is on purpose
The NEXT_PUBLIC_ prefix means it is sent to the browser, which is correct:
it is an address, not a secret. Reaching the deployment still requires the
signed session that only your users have.
SETTINGS_SECRET
The key that seals other people's tokens: a GitHub access token, a gateway key, a webhook signing secret. The vault encrypts values with it before they are stored, so a database dump is not a list of everybody's keys.
Where it comes from. Any long random string. openssl rand -base64 32 is the shortest way to make one.
What breaks without it. Nothing can be connected, stored or renewed. Integrations and stored credentials appear switched off.
Changing it unseals nothing
Every stored token becomes unreadable the moment this changes: they are not re-encrypted, they are simply unreadable, because the key that opens them is gone. Rotate it deliberately, then reconnect the integrations. Sealed values are never printed back to you, not even to the owner.
GITHUB_CONNECT_CLIENT_ID and GITHUB_CONNECT_CLIENT_SECRET
GitHub sign in and GitHub push are two different applications, and this pair is the second one. It belongs to the installation rather than to any one user, which is what makes it possible for somebody to save their work to a repository of their own without bringing their own GitHub application.
Where it comes from. GitHub, then Settings → Developer settings → OAuth Apps, with the callback
https://your-app-address/api/connect/github/callbackWhat breaks without it. The Connectors screen shows GitHub as unavailable, with the reason, instead of a button that fails when pressed. Sign in using GitHub is unaffected: that is the other application.
NEXT_PUBLIC_APP_URL
This app's own address. It is used to build the address a provider sends somebody back to, the links in emails, and the origin the connect flow is allowed to return to.
Where it comes from. You. https://loomis.your-domain.com in production, http://localhost:3000 on a
laptop.
What breaks without it. OAuth returns land on the wrong host, and saved links point at a machine that is not yours. This is the name people most often forget when they move an installation to a server.
AI_GATEWAY_API_KEY
The one key every model in the catalogue is reached through. Loomis does not talk to each vendor separately: it asks the gateway, the gateway asks whichever model a turn picked, and one bill covers the lot.
Where it comes from. Vercel, then AI Gateway, then API keys. It is read by the app rather than by the deployment, because the route that streams an answer runs in the Next.js process.
What breaks without it. No turn is written at all. The chat, the agent pane, the picture tools and every
search stop together, and the failure looks like a broken model rather than a missing key. System → Health
calls the gateway's own model list to tell you which one it is.
ALLOW_SELF_UPDATE
The switch that lets System → Setup & licensing update this installation by running git, pnpm and the Convex
CLI in the folder the app lives in.
Where it comes from. You decide. 1 on a host whose folder you own, and left unset anywhere else.
What breaks without it. Nothing. The update screen still checks for a newer copy and still shows the exact commands, and you run them yourself. That is the honest answer for a host with no shell, which is why this is off by default and why it is one of the two optional names.
Setting them
# the walk, which knows all seven
pnpm configure --only=app
# or by hand, in .env.local
NEXT_PUBLIC_CONVEX_URL=https://quick-fox-1234.convex.cloud
SETTINGS_SECRET=a-long-random-string
NEXT_PUBLIC_APP_URL=http://localhost:3000
AI_GATEWAY_API_KEY=your-gateway-keyTwo Node processes, one file
pnpm dev reads .env.local when it starts, so a change needs the server
restarted. A production host reads it when the process starts, which is why a
change there means a restart of the service rather than a redeploy.

