permaweb-deploy
v4.0.0
Published
Permaweb App Deployment Package
Downloads
2,321
Readme
Permaweb Deploy
Inspired by the cookbook github action deployment guide, permaweb-deploy is a Node.js command-line tool designed to streamline the deployment of web applications to the permaweb using Arweave. It uploads your build folder or a single file, creates Arweave manifests, and can optionally update ArNS (Arweave Name Service) records via ANT (Arweave Name Token) with the transaction ID.
Features
- Turbo SDK Integration: Uses Turbo SDK for fast, reliable file uploads to Arweave
- On-Demand Payment: Pay with ARIO or Base-ETH tokens on-demand during upload
- Arweave Manifest v0.2.0: Creates manifests with fallback support for SPAs
- Optional ArNS Updates: Updates ArNS records via ANT with new transaction IDs and metadata
- Automated Workflow: Integrates with GitHub Actions for continuous deployment
- Git Hash Tagging: Automatically tags deployments with Git commit hashes
- 404 Fallback Detection: Automatically detects and sets 404.html as fallback
- Network Support: Supports mainnet, testnet, and custom ARIO process IDs
- Flexible Deployment: Supports deploying a folder or a single file
- Modern CLI: Built with oclif for a robust command-line experience
- TypeScript: Fully typed for better developer experience
Installation
Install the package using pnpm (recommended):
pnpm add -D permaweb-deployOr with npm:
npm install --save-dev permaweb-deployOr with yarn:
yarn add --dev permaweb-deployPrerequisites
For Arweave signer (default): Encode your Arweave wallet key in base64 format and set it as a GitHub secret:
base64 -i wallet.json | pbcopyFor Ethereum/Polygon/KYVE signers: Use your raw private key (no encoding needed) as the
DEPLOY_KEY.Ensure that the secret name for the encoded wallet or private key is
DEPLOY_KEY.
⚠️ Important: Use a dedicated wallet for deployments to minimize security risks. Ensure your wallet has sufficient Turbo Credits for uploads.
Usage
Interactive Mode (Easiest)
Command Menu:
Simply run the CLI for an interactive command selector:
permaweb-deploy
# or explicitly
permaweb-deploy interactiveThis shows a menu with options:
- Deploy to Permaweb - Start the deployment wizard
- Show Help - Display help information
- Exit - Exit the CLI
Interactive Deploy (Guided):
Run the deploy command without arguments to be guided through all deployment options:
permaweb-deploy deployThis uploads to the permaweb by default. Use --use-arns or --arns-name to run the guided ArNS update flow, which will prompt you for:
- ArNS name
- Wallet method (file, string, or environment variable)
- Signer type (Arweave, Ethereum, Polygon, KYVE)
- What to deploy (folder or file)
- Advanced options (optional: undername, TTL, network)
Direct Commands
Use flags for faster, scriptable deployments:
# Basic deployment with wallet file
permaweb-deploy deploy --wallet ./wallet.json
# Deployment with ArNS update
permaweb-deploy deploy --use-arns --arns-name my-app --wallet ./wallet.jsonDeploy using private key directly:
permaweb-deploy deploy --arns-name my-app --private-key "$(cat wallet.json)"Deploy using environment variable:
DEPLOY_KEY=$(base64 -i wallet.json) permaweb-deploy deploy --arns-name my-appDeploy a specific folder:
permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json --deploy-folder ./buildDeploy a single file:
permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json --deploy-file ./path/to/file.txtUpload/deploy without ArNS
deploy uploads without updating ArNS by default. You can also use the upload command explicitly for the same Turbo upload, dedupe cache, and payment options as deploy, minus ArNS flags:
permaweb-deploy deploy --wallet ./wallet.json --deploy-folder ./dist
permaweb-deploy upload --wallet ./wallet.json --deploy-folder ./dist
permaweb-deploy upload --wallet ./wallet.json --deploy-file ./dist/index.html
DEPLOY_KEY=$(base64 -i wallet.json) permaweb-deploy upload --deploy-folder ./distAdvanced Usage
Deploy to an undername (subdomain):
permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json --undername stagingDeploy with a custom TTL:
permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json --ttl-seconds 7200Deploy using Ethereum wallet (file):
permaweb-deploy deploy --arns-name my-app --sig-type ethereum --wallet ./private-key.txtDeploy using Ethereum wallet (direct key):
permaweb-deploy deploy --arns-name my-app --sig-type ethereum --private-key "0x1234..."On-Demand Payment
Use on-demand payment to automatically fund uploads with ARIO or Base-ETH tokens when your Turbo balance is insufficient:
Deploy with ARIO on-demand payment:
permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json --on-demand ario --max-token-amount 1.5Deploy with Base-ETH on-demand payment (using Ethereum signer):
permaweb-deploy deploy --arns-name my-app --sig-type ethereum --private-key "0x..." --on-demand base-eth --max-token-amount 0.1On-Demand Payment Options:
--on-demand: Token to use for on-demand payment (arioorbase-eth)--max-token-amount: Maximum token amount to spend (in native token units, e.g.,1.5for 1.5 ARIO or0.1for 0.1 ETH)
How it works:
- Checks your Turbo balance before upload
- If balance is insufficient, converts tokens to Turbo credits on-demand
- Automatically adds a 10% buffer (
topUpBufferMultiplier: 1.1) for reliability - Proceeds with upload once funded
Token compatibility:
- ARIO: Works with Arweave signer
- Base-ETH: Works with Ethereum signer (Base Network)
Bundler service
Uploads go through a bundler service that accepts signed data items and posts them to Arweave. By default, permaweb-deploy uses the Turbo API and ArDrive’s production bundler (https://upload.ardrive.io). --uploader sets the base URL of the bundler service to use (scheme + host; typically no path).
| When to use | Example value |
| ------------------------- | ----------------------------------------------------------------- |
| Default (omit flag) | ArDrive production bundler — same as Turbo CLI defaults |
| Arweave bundler | https://up.arweave.net |
| Development / staging | https://upload.ardrive.dev |
| Custom or self-hosted | Your own base URL if it implements the selected uploader protocol |
Examples:
# Deploy using Arweave’s bundler service
permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json --uploader https://up.arweave.net
permaweb-deploy upload --wallet ./wallet.json --deploy-folder ./dist --uploader https://up.arweave.netTo upload through a HyperBEAM bundler, set --uploader-type hyperbeam and pass the node URL:
permaweb-deploy upload \
--wallet ./wallet.json \
--deploy-folder ./dist \
--uploader-type hyperbeam \
--uploader https://hyperbeam.example.com
permaweb-deploy deploy \
--wallet ./wallet.json \
--deploy-folder ./dist \
--uploader-type hyperbeam \
--uploader https://hyperbeam.example.comIf the node follows the standard AO-paid HyperBEAM bundler flow, either command can fund the uploader wallet before uploading:
permaweb-deploy upload \
--wallet ./wallet.json \
--deploy-folder ./dist \
--uploader-type hyperbeam \
--uploader https://hyperbeam.example.com \
--hyperbeam-auto-fundNotes:
- Turbo billing and signer behavior follow Turbo.
- HyperBEAM uploads require an Arweave JWK signer. Before uploading, the CLI checks the node address from
/[email protected]/info/addressagainsthttps://arweave.net/wallet/<address>/balanceand aborts if the bundler wallet has 0 AR. With--hyperbeam-auto-fund, the CLI signs each data item, asks the node's byte-pricing profile for a quote, sends AO to the node deposit address, imports that deposit through/[email protected]/ingest, and waits for the uploader's balance at/[email protected]/now/balance/<address>before uploading. The default route is/[email protected]/[email protected]; override it with--hyperbeam-upload-pathif your node exposes a different bundler route. --hyperbeam-fund-amountis an optional override for the minimum local ledger balance to ensure, in AO base units. Without it,--hyperbeam-auto-funduses the node's byte-pricing quote for the signed byte count. Use--hyperbeam-token-idonly for a non-default AO token process, and--hyperbeam-ledger-idonly for a non-default local ledger profile.- Use a base URL only (e.g.
https://up.arweave.netorhttps://hyperbeam.example.com), not a path to a specific file or route.
Command Options
deploy (upload by default, optional ArNS update):
--use-arns: Update an ArNS/ANT record after upload--arns-name, -n: The ArNS name to update. Required when using--use-arns; also implies ArNS mode for backwards compatibility.--ario-process, -p: ARIO process to use (mainnet,testnet, or a custom process ID). Default:mainnet--deploy-folder, -d: Folder to deploy. Default:./dist--deploy-file, -f: Deploy a single file instead of a folder--undername, -u: ANT undername to update. Default:@--ttl-seconds, -t: TTL in seconds for the ANT record (60-86400). Default:60--sig-type, -s: Signer type for deployment. Choices:arweave,ethereum,polygon,kyve. Default:arweave--wallet, -w: Path to wallet file (JWK for Arweave, private key for Ethereum/Polygon/KYVE)--private-key, -k: Private key or JWK JSON string (alternative to--wallet)--on-demand: Enable on-demand payment with specified token. Choices:ario,base-eth--max-token-amount: Maximum token amount for on-demand payment (used with--on-demand)--no-dedupe: Disable deduplication (do not cache or reuse previous uploads)--dedupe-cache-max-entries: Maximum number of entries to keep in the dedupe cache (LRU). Default:10000--uploader: Base URL of the bundler service to use. See Bundler service above.--uploader-type: Upload protocol to use (turboorhyperbeam). Default:turbo--hyperbeam-upload-path: HyperBEAM bundler route. Default:/[email protected]/[email protected]--hyperbeam-auto-fund: Automatically fund the HyperBEAM local ledger before upload--hyperbeam-fund-amount: Optional minimum HyperBEAM local ledger balance override, in token base units--hyperbeam-token-id: Advanced AO token process ID override--hyperbeam-ledger-id: Advanced local HyperBEAM ledger ID override--hyperbeam-ao-state-url: AO state endpoint used while waiting for auto-fund transfer assignment. Default:https://state.forward.computer
upload (explicit upload without ArNS): accepts --deploy-folder, --deploy-file, wallet/signer flags, uploader flags, --on-demand / --max-token-amount, and dedupe flags only.
Deduplication
By default, permaweb-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, permaweb-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
- Only new or modified files are uploaded to Arweave
- The cache is stored locally in
.permaweb-deploy/transaction-cache.json
Disable deduplication:
If you need to force a fresh upload of all files (e.g., for debugging or to ensure a completely new deployment):
permaweb-deploy deploy --arns-name my-app --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:
# Keep only the last 1000 file entries
permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json --dedupe-cache-max-entries 1000Cache location:
The cache file is stored at .permaweb-deploy/transaction-cache.json 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 .permaweb-deploy/
Package.json Scripts
Add deployment scripts to your package.json:
{
"scripts": {
"build": "vite build",
"deploy": "pnpm build && permaweb-deploy deploy --arns-name <ARNS_NAME>",
"deploy:staging": "pnpm build && permaweb-deploy deploy --arns-name <ARNS_NAME> --undername staging",
"deploy:testnet": "pnpm build && permaweb-deploy deploy --arns-name <ARNS_NAME> --ario-process testnet",
"deploy:on-demand": "pnpm build && permaweb-deploy deploy --arns-name <ARNS_NAME> --on-demand ario --max-token-amount 1.5"
}
}Then deploy with:
DEPLOY_KEY=$(base64 -i wallet.json) pnpm deployOr with on-demand payment:
DEPLOY_KEY=$(base64 -i wallet.json) pnpm deploy:on-demandGitHub Action
The easiest way to integrate permaweb-deploy into your CI/CD pipeline is using our official GitHub Action.
Basic Usage
- uses: permaweb/permaweb-deploy@v1
with:
deploy-key: ${{ secrets.DEPLOY_KEY }}
arns-name: myapp
deploy-folder: ./distPR Preview Deployments
Automatically deploy preview builds for each pull request. The preview mode auto-generates an undername from the PR number and posts a comment with the preview URL:
name: Deploy PR Preview
on:
pull_request:
types: [opened, synchronize]
jobs:
deploy-preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Deploy Preview
uses: permaweb/permaweb-deploy@v1
with:
deploy-key: ${{ secrets.DEPLOY_KEY }}
arns-name: myapp
preview: 'true'
github-token: ${{ secrets.GITHUB_TOKEN }}
deploy-folder: ./distWhen preview is enabled, the action will:
- Auto-generate an undername like
pr-123from the PR number - Post a comment on the PR with the preview URL
- Update the comment on subsequent pushes instead of creating new ones
Production Deployment
Deploy to your base ArNS name when pushing to main:
name: Deploy to Production
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Deploy to Permaweb
uses: permaweb/permaweb-deploy@v1
with:
deploy-key: ${{ secrets.DEPLOY_KEY }}
arns-name: myapp
deploy-folder: ./distWith On-Demand Payment
- name: Deploy with ARIO on-demand
uses: permaweb/permaweb-deploy@v1
with:
deploy-key: ${{ secrets.DEPLOY_KEY }}
arns-name: myapp
deploy-folder: ./dist
on-demand: ario
max-token-amount: '2.0'With HyperBEAM
- name: Deploy through a HyperBEAM bundler
uses: permaweb/permaweb-deploy@v1
with:
deploy-key: ${{ secrets.DEPLOY_KEY }}
arns-name: myapp
deploy-folder: ./dist
uploader-type: hyperbeam
uploader: https://hyperbeam.example.com
hyperbeam-auto-fund: 'true'Disabling Deduplication
By default, the action caches transaction IDs to avoid re-uploading unchanged files. To disable this:
- name: Deploy without dedupe
uses: permaweb/permaweb-deploy@v1
with:
deploy-key: ${{ secrets.DEPLOY_KEY }}
arns-name: myapp
deploy-folder: ./dist
no-dedupe: 'true'You can also limit the cache size:
- name: Deploy with limited cache
uses: permaweb/permaweb-deploy@v1
with:
deploy-key: ${{ secrets.DEPLOY_KEY }}
arns-name: myapp
deploy-folder: ./dist
dedupe-cache-max-entries: '1000'CLI in GitHub Actions
You can also use the CLI directly in your workflows:
Basic Workflow:
name: Deploy to Permaweb
on:
push:
branches:
- main
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install
- run: pnpm deploy
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}With On-Demand Payment:
name: Deploy to Permaweb with On-Demand Payment
on:
push:
branches:
- main
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install
- run: pnpm build
- name: Deploy with ARIO on-demand
run: permaweb-deploy deploy --arns-name my-app --on-demand ario --max-token-amount 2.0
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
# Or deploy with Ethereum and Base-ETH:
# - name: Deploy with Base-ETH on-demand
# run: |
# permaweb-deploy deploy \
# --arns-name my-app \
# --sig-type ethereum \
# --on-demand base-eth \
# --max-token-amount 0.2
# env:
# DEPLOY_KEY: ${{ secrets.ETH_PRIVATE_KEY }}Development
Setup
# Install dependencies
pnpm install
# Build the project
pnpm build
# Run in development mode
pnpm dev
# Run tests
pnpm test
# Run linter
pnpm lint
# Format code
pnpm formatProject Structure
permaweb-deploy/
├── src/
│ ├── commands/ # oclif commands
│ │ ├── deploy.ts
│ │ └── upload.ts
│ ├── types/ # TypeScript type definitions
│ │ └── index.ts
│ ├── utils/ # Utility functions
│ │ ├── constants.ts
│ │ ├── signer.ts
│ │ ├── uploader.ts
│ │ └── __tests__/ # Unit tests
│ └── index.ts # Main entry point
├── bin/ # Executable scripts
│ ├── run.js
│ └── dev.js
├── .changeset/ # Changesets configuration
├── .husky/ # Git hooks
└── dist/ # Build outputSecurity & Best Practices
- Dedicated Wallet: Always use a dedicated wallet for deployments to minimize security risks
- Wallet Encoding: Arweave wallets must be base64 encoded to be used in the deployment script
- ArNS Name: Required only when updating an ANT/ArNS target undername or root record
- Turbo Credits: Ensure your wallet has sufficient Turbo Credits, or use on-demand payment for automatic funding
- On-Demand Limits: Set reasonable
--max-token-amountlimits to prevent unexpected costs - Secret Management: Keep your
DEPLOY_KEYsecret secure and never commit it to your repository - Build Security: Always check your build for exposed environmental secrets before deployment, as data on Arweave is permanent
Troubleshooting
- Error: "DEPLOY_KEY environment variable not set": Verify your base64 encoded wallet is set as the
DEPLOY_KEYenvironment variable - Error: "deploy-folder does not exist": Check that your build folder exists and the path is correct
- Error: "deploy-file does not exist": Check that your build file exists and the path is correct
- Error: "ArNS name does not exist": Verify the ArNS name is correct and exists in the specified network
- Upload timeouts: Files have a timeout for upload. Large files may fail and require optimization
- Insufficient Turbo Credits: Use
--on-demandwith--max-token-amountto automatically fund uploads when balance is low - On-demand payment fails: Ensure your wallet has sufficient tokens (ARIO or Base-ETH) and the token type matches your signer (
ariowith Arweave,base-ethwith Ethereum)
Contributing
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests and linter:
pnpm test && pnpm lint - Create a changeset:
pnpm changeset - Commit your changes using conventional commits
- Push and create a pull request
Conventional Commits
This project uses Conventional Commits. Commit messages should follow this format:
type(scope): subject
body (optional)Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
Changesets
We use changesets for version management. When making changes:
pnpm changesetFollow the prompts to describe your changes.
Dependencies
- @ar.io/sdk - For ANT operations and ArNS management
- @ardrive/turbo-sdk - For fast file uploads to Arweave
- @permaweb/aoconnect - For AO network connectivity
- @oclif/core - CLI framework
- mime-types - MIME type detection
License
ISC
Author
NickJ202
