Configuration
The CLI reads its configuration from three places, in this order of precedence:
CLI flags > environment variables > .appilotsrc file
sync and status work with only environment variables set — no
.appilotsrc needed at all — which is what makes CI-only setups possible
(see CI integration). watch is the one exception: it
currently requires an actual .appilotsrc file to exist; environment-only
config is not supported for watch.
.appilotsrc
A JSON file, one per project, written by appilots init and read by every
other command.
| Field | Type | Required | Description |
|---|---|---|---|
apiKey | string | Yes | Appilots API key. Must start with ak_ |
serverUrl | string | Yes (defaults to http://localhost:4000 if omitted) | See production URL below |
projectId | string | No | Informational — the API key alone identifies the project server-side. Used for the dashboard link sync prints |
outputDir | string | No | Where generate/sync/watch write the local MCP document and checksum cache. Default .appilots |
include | string[] | No | Glob patterns for source files included in analysis |
exclude | string[] | No | Glob patterns for source files excluded from analysis |
autoActivate | boolean | No | Whether the uploaded document is automatically made active. Default true |
strictScreens | boolean | No | When true, only files matching screenPatterns (or containing a registerScreen() call) are treated as screens. Default true |
screenPatterns | string[] | No | Glob patterns used with strictScreens. Default ['**/*Screen.{ts,tsx}', '**/screens/**/*.{ts,tsx}'] |
navigationInclude | string[] | No | Additional glob patterns for navigation-file discovery. Added to the defaults, not a replacement |
navigationExclude | string[] | No | Glob patterns excluded from navigation-file discovery |
platform | string | No | Source analyzer to run. react-native (default) reads React Navigation; web reads React screens and React Router routes (see Web SDK quick start). Any other value skips source analysis, so every screen must come from the manifest |
manifestPath | string | No | Path to a declared screens file, merged over the analyzer output. Default appilots.manifest.json. See Manifest mode |
Example
{
"apiKey": "ak_xxxxxxxxxxxx...",
"projectId": "proj_xxxxxxxx",
"serverUrl": "https://api.appilots.com",
"outputDir": ".appilots",
"autoActivate": true,
"strictScreens": true
}
Unrecognized fields
Any key the CLI does not know is ignored, and the default is used instead.
That is quiet enough to be dangerous — writing apiUrl instead of
serverUrl leaves the CLI talking to http://localhost:4000 and the
resulting failure looks like a network problem, not a typo. Every command
that loads config now warns about keys it does not recognize, with a
suggestion when the intent is guessable:
⚠ /path/to/.appilotsrc: unknown key "apiUrl" — ignored (did you mean "serverUrl"?)
The warning is not fatal: the command carries on with the defaults.
Discovery
appilots looks for .appilotsrc by walking up from the current
working directory to the filesystem root, the same way .npmrc lookup
works. That means you can run appilots sync from any subdirectory of a
project and it will find the config at the project root.
Environment variables
| Variable | Overrides |
|---|---|
APPILOTS_PUBLISH_KEY | apiKey (takes precedence over APPILOTS_API_KEY) |
APPILOTS_API_KEY | apiKey |
APPILOTS_PROJECT_ID | projectId |
APPILOTS_SERVER_URL | serverUrl |
Blank or whitespace-only values are treated as unset.
Production server URL
The CLI's built-in default for serverUrl is http://localhost:4000 — a
dev-oriented default for running against a self-hosted server locally. If
neither serverUrl in .appilotsrc, APPILOTS_SERVER_URL, nor --server
is set, this is what the CLI will fall back to. Always set serverUrl
explicitly to https://api.appilots.com for anything other than local
development — don't let the raw default end up in a production CI
pipeline.
When a command cannot reach the server, the error names the server it tried and why:
✗ Sync failed: Cannot reach Appilots server at http://localhost:4000 (ECONNREFUSED)
ℹ serverUrl is not set, so the CLI is using the built-in default (http://localhost:4000)
With or without /api/v1
Both spellings work:
{ "serverUrl": "https://api.appilots.com" }
{ "serverUrl": "https://api.appilots.com/api/v1" }
The API is mounted under /api/v1, and the CLI now completes that prefix
when it is missing rather than assuming it is absent. A gateway that mounts
Appilots under a path of its own
(https://gw.acme.com/appilots/api/v1) is left alone.
This used to be origin-only: the CLI appended /api/v1 to whatever you
wrote, so the prefixed spelling produced /api/v1/api/v1/cli/sync and a 404. That was its own kind of wrong, because the SDK reads this same
file and needed the opposite — a spelling that made sync work broke the
agent, and vice versa.
The SDK reads this field too
serverUrl points both the CLI and @appilots/sdk at the same API. The
SDK used to know only its own apiBaseUrl and silently ignored serverUrl,
so an app configured for staging or a local stack kept talking to
production with nothing on screen to say so.
If you set both, apiBaseUrl wins — it is the SDK's own key, so writing it
is the more specific statement of intent. You do not need both.
How the CLI authenticates
Every CLI command authenticates with a project publish key (ak_…,
scope publish) and talks to the /cli/* routes. This is not the key
your app ships with: an sdk key is rejected with 401 ("SDK keys cannot
authorize CLI operations"). Create a publish key under Workspace → API
keys and pass it through APPILOTS_PUBLISH_KEY (or --api-key). The
key identifies the project, which is why projectId is informational.
.appilotsrcThe SDK also reads .appilotsrc, and its apiKey ends up inside your app
bundle. Keep the app's sdk key there and give the CLI the publish key
through the environment, so the private key never ships to devices.
The dashboard's own MCP-document routes (/mcp-documents/*) use a
different scheme: a user login token plus a workspace header. They are not
interchangeable, and deliberately so — a project key is bound to one
project, while those routes can list, activate and delete
documents across every project in the workspace. Sending an ak_… key
there answers:
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "This endpoint requires a dashboard user token; received a project API key (ak_...) ..."
}
}
Nothing in the CLI needs those routes. If you are calling them yourself,
get a token from POST /auth/login and send X-Workspace-Id.
Security
.appilotsrc holds your API key in plaintext.
appilots initautomatically appends.appilotsrcto.gitignorewhen one exists, and warns loudly if it can't (no.gitignorepresent).- Verify it's actually ignored before committing anything in that
directory — never commit
.appilotsrc. - For CI, prefer environment variables / your CI provider's secret store
over a committed config file — see CI integration.
APPILOTS_API_KEYis part of the CLI's own public config surface (it's meant to be set, just like.appilotsrc'sapiKeyfield), but its value should be handled like any other credential.