# Files (https://hotcodepush.com/docs/cli/files)

What config.json, the keyring entry, hotcodepush.json, the resource file and the private key file hold, where each lives per OS and who writes it.

The CLI keeps five things on disk, listed below with where each one lives.
Nothing else: no `.hotcodepush` directory in the project and no private key the CLI keeps for itself.

| File | Holds | Where |
|---|---|---|
| `config.json` | Holds the API URL, the session id, the update-check fields, a pending login, the telemetry-notice timestamp, and the token only where no keyring works. | the user's config directory |
| the keyring entry | Holds the session token `login` stored. | the OS secure storage |
| `hotcodepush.json` | Holds the app id, the channel by name, the public keys, the SDK options and `extraFingerprintPaths`. | the project root, committed |
| the resource file | Holds `hotcodepush.json` minus the CLI's keys, plus the build-time facts. | the built app, written by every build, never committed |
| the private key file | Holds the RSA private key of a signing key pair, PEM, PKCS #8. | where `signing-key create` wrote it, out of version control |

## config.json [#configjson]

The user's config directory is `~/.config/hotcodepush` on macOS and Linux, `$XDG_CONFIG_HOME/hotcodepush` when that variable is set, and `%APPDATA%\hotcodepush` on Windows.
The file is written with mode `0600` on macOS and Linux, since it can hold the token. One that does not parse is [`invalid_json`](https://hotcodepush.com/docs/cli/errors#invalid_json).

| Key | Written by | Holds |
|---|---|---|
| `apiUrl` | `login --api-url` | Names the API every command talks to. Defaults to production. |
| `lastUpdateCheckAt`, `latestKnownVersion` | the daily update check | Hold when the npm registry was last asked and what it answered. |
| `pending*` | a `login` that could not wait | Hold the device authorization the next `login` redeems or shows again. |
| `sessionExpiresAt` | `login`, renewed when a command finds it passed and the API still knows the session | Holds when the session ends, the hint that makes a command ask to log in again. |
| `sessionId` | `login` | Holds the session's non-secret id, which `logout` deletes. |
| `telemetryNoticeShownAt` | the first command on the machine | Records that the [telemetry notice](https://hotcodepush.com/docs/cli/telemetry) was printed. |
| `token` | `login`, only where no keyring backend works | Holds the session token, the fallback for headless machines. |

## The keyring entry [#the-keyring-entry]

The session token lives in the OS secure storage: the macOS Keychain, the Windows Credential Manager or the Secret Service on Linux.
The entry is under the service `hotcodepush-cli` and the account `token`.

Where no keyring backend works, headless CI the usual case, the token goes into `config.json` instead.
The `HOTCODEPUSH_TOKEN` variable wins over both, and `logout` deletes the entry and the fallback while leaving the variable alone.

## hotcodepush.json [#hotcodepushjson]

`hotcodepush.json` is the project's configuration, next to `package.json`, written by [`init`](https://hotcodepush.com/docs/cli/commands/init) and read by every command. `--config <path>` names it when it lies elsewhere.
Running `init` writes `appId` and `channel`. Every command finds the file walking up from the working directory, so the CLI runs from any folder of the repository.
Every other key is an SDK option, listed on the configuration pages for [React Native](https://hotcodepush.com/docs/sdks/react-native/configuration), [Expo](https://hotcodepush.com/docs/sdks/expo/configuration), [Capacitor](https://hotcodepush.com/docs/sdks/capacitor/configuration) and [Cordova](https://hotcodepush.com/docs/sdks/cordova/configuration).

```json title="hotcodepush.json"
{
  "appId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "channel": "production"
}
```

| Key | Written by | Read by |
|---|---|---|
| `appId` | `init` | Every command reads it, as the default for `--app`. |
| `channel` | `init`, the app's default channel by name | `release create`, the build steps and every verb that takes `--channel` read it, as the default. Defaults to `production` when absent. |
| `extraFingerprintPaths` | you | The fingerprint reads it and hashes the files under these paths beside the native packages. It is the one key that never reaches a device. |
| `publicKeys` | `signing-key create` and `signing-key add` append, `signing-key delete` removes | An upload reads it and signs when the list is not empty, and the build steps write the keys into the resource file. |

The CLI keeps the file's indentation when it edits it, and `doctor` reports a file that does not parse as a failed `configuration` check.

## The resource file [#the-resource-file]

The resource file is what the SDK reads at runtime: `hotcodepush.json` without `channel` and `extraFingerprintPaths`, plus what only a build can know.
The SDK package's Xcode phase and Gradle task write it into every native build: [`binary create`](https://hotcodepush.com/docs/cli/commands/binary) in a store build, [`resource-file write`](https://hotcodepush.com/docs/cli/commands/resource-file) in every other build.
It describes one build, so it is never committed.

| Key | Holds |
|---|---|
| `appId`, `publicKeys`, the SDK options | Come from `hotcodepush.json`, the public keys re-encoded as `{ "der", "keyId" }` in the form the platform's own API imports, PKCS #1 on iOS and SPKI on Android. |
| `builtAt` | Holds the build's time. No release older than it is applied. |
| `channelId` | Holds the channel resolved to its id through the API, or `null` when the build ran offline or without a token and the project names the channel by name. |
| `embeddedBundleId` | Holds the bundle's id once a store build created its binary, or `null` from `resource-file write`. |
| `embeddedBundleManifest` | Holds the embedded bundle's files with path, hash and size, or `null` for a React Native or Expo debug build that bundled nothing. |
| `filesBaseUrl`, `updatesBaseUrl` | Hold the hosts the device reads from, written only when they differ from production's. `HOTCODEPUSH_FILES_BASE_URL` and `HOTCODEPUSH_UPDATES_BASE_URL` set them. |
| `fingerprint` | Holds the native fingerprint the build was made on. |

[How an update reaches a device](https://hotcodepush.com/docs/concepts/update-delivery) explains what the SDK does with the file.

## The private key file [#the-private-key-file]

`signing-key create` writes the private key of a new pair to `hotcodepush-private-key.pem` in the working directory, or to `--private-key-path`, with mode `0600` on macOS and Linux.
The CLI never prints the key, never keeps a copy and never looks for the file.

An upload gets the key through `--private-key-path`, or from `HOTCODEPUSH_SIGNING_KEY` in CI.
Keep the file out of version control. [Sign your bundles](https://hotcodepush.com/docs/guides/code-signing) covers the rotation.

## Temporary files [#temporary-files]

An upload writes its gzip copies and the full pack under a `hotcodepush-` directory in the system's temporary folder, removed when the command ends.
The file `hotcodepush fingerprint --json > <file>` writes is one you keep, the input of [`fingerprint diff`](https://hotcodepush.com/docs/cli/commands/fingerprint#diff).
