Deduplication
By default, ario-deploy caches your deployment log to prevent uploading duplicate (unchanged) files. This saves both time and upload costs by reusing existing data on Arweave.
How it works:
- When you deploy, ario-deploy hashes each file in your build
- It checks the local cache for matching hashes from previous uploads
- Files that haven't changed are skipped - the existing transaction ID is reused
- Files identical to another file in the same deploy are uploaded once and share its transaction (static exports often write the same payload under several names)
- Only new or modified files are uploaded to Arweave, and each id is written to the cache the moment it lands, so a deploy that fails or is interrupted part-way does not pay for those files again
- The cache is stored locally in
.ario-deploy/transaction-cache.json, with a separate file per Turbo network (--devuploads never stand in for production ones)
Entries are keyed on the file's content and content type (plus encoding when compressed), so byte-identical files served as different types are never confused. Caches written by 1.x, keyed on the hash alone, are still honoured, except for empty files, whose hash says nothing about their type.
Symlinks inside the deploy folder are followed only while they point inside it; a link to a file outside the folder stops the deploy, since uploading it would publish that file permanently.
Files that are never uploaded
The check is built to stop a key from being published by accident. It cannot promise to find a key that someone disguises on purpose (reversed, split across files, or in an encoding of their own), so keep keys outside the project folder.
Before any request is made, deploy and upload list the files once, read every one of them and refuse to publish a private key. Only the files that were checked are uploaded. The error names the file and never prints the key. There is no flag to override this.
Keys the run holds. Every key the command was given (--wallet, --arns-wallet, --private-key, --arns-private-key, DEPLOY_KEY and ARNS_KEY, whichever are set) is searched for in every file and every file name. The search covers:
- the key's raw bytes, hex in any case (also as
0x0c, 0x22,\x0c\x22or0c:22), a decimal byte list such as[12, 34, ...], base58, and base64 or base64url at any alignment - an Arweave key's private JWK fields, the base64 JWK that
DEPLOY_KEYholds, and each key file base64-encoded, as in adata:URI - text with spaces, line breaks, string concatenation,
\u,\xand percent escapes removed, UTF-16 text, every string of a JSON file, and printable text inside binary files
Gzip, brotli (.br), zip and tar files are opened and searched, including archives inside archives up to three levels deep. A compressed file is refused as one that could not be checked when it expands to more than 1 GiB, is nested deeper, is damaged or encrypted, or is a 7z, RAR, xz, bzip2, Zstandard or cabinet archive. The run also stops when a wallet file, or a hard link or symlink to one, is inside the deploy folder or is the --deploy-file.
Keys the run does not hold. The run also stops on what can be proved to be a private key, in files and inside the archives above:
- an environment file:
.env,.env.local,.env.example,prod.env, in any case (scripts and pages such asenv.jsare not refused for their name) - a PEM private key block (
-----BEGIN PRIVATE KEY-----and the RSA, EC, DSA, OPENSSH and ENCRYPTED forms); public keys and certificates are not refused - a Solana keypair written as a byte array, base58 or hex, checked by deriving its public half from its seed
- an object with a private exponent
dand an RSA-sized modulusn(2048 bits or more) together, as JSON, inside a string or base64-encoded
What is not detected for a key the run does not hold: a 32-byte seed or an Ethereum key on its own in any form (it cannot be told from a hash), brotli data without a .br name, and keys inside compressed parts of other formats, such as PNG text chunks or PDF streams.
.git folders are left out of folder uploads, with a one-line note.
The Turbo credit check runs after this planning step, so it prices only what will actually be uploaded, not the whole folder.
Disable deduplication:
If you need to force a fresh upload of all files (e.g., for debugging or to ensure a completely new deployment). Files that are identical within the same deploy are still uploaded once and share a transaction, since that reuses nothing from earlier deploys:
ario-deploy deploy --wallet ./wallet.json --no-dedupeLimit cache size:
The dedupe cache uses an LRU (Least Recently Used) eviction strategy. By default, it keeps up to 10,000 entries. You can adjust this limit:
ario-deploy deploy --wallet ./wallet.json --dedupe-cache-max-entries 1000Cache location:
The cache files are stored in .ario-deploy/ in your project root. You can:
- Add it to
.gitignoreif you don't want to share cache across team members - Commit it to share cached transaction IDs with your team (reduces duplicate uploads)
- Delete it to start fresh:
rm -rf .ario-deploy/
How is this guide?