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 updates ArNS (Arweave Name Service) records via ANT (Arweave Name Token) with the transaction ID.
- 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
- 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
Install the package using pnpm (recommended):
pnpm add -D permaweb-deploy
Or with npm:
npm install --save-dev permaweb-deploy
Or with yarn:
yarn add --dev permaweb-deploy
-
For Arweave signer (default): Encode your Arweave wallet key in base64 format and set it as a GitHub secret:
base64 -i wallet.json | pbcopy
-
For 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
.
Command Menu:
Simply run the CLI for an interactive command selector:
permaweb-deploy
# or explicitly
permaweb-deploy interactive
This 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 deploy
This 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)
Use flags for faster, scriptable deployments:
# Basic deployment with wallet file
permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json
Deploy 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-app
Deploy a specific folder:
permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json --deploy-folder ./build
Deploy a single file:
permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json --deploy-file ./path/to/file.txt
Deploy to an undername (subdomain):
permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json --undername staging
Deploy with a custom TTL:
permaweb-deploy deploy --arns-name my-app --wallet ./wallet.json --ttl-seconds 7200
Deploy using Ethereum wallet (file):
permaweb-deploy deploy --arns-name my-app --sig-type ethereum --wallet ./private-key.txt
Deploy using Ethereum wallet (direct key):
permaweb-deploy deploy --arns-name my-app --sig-type ethereum --private-key "0x1234..."
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.5
Deploy 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.1
On-Demand Payment Options:
--on-demand
: Token to use for on-demand payment (ario
orbase-eth
)--max-token-amount
: Maximum token amount to spend (in native token units, e.g.,1.5
for 1.5 ARIO or0.1
for 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)
--arns-name, -n
(required): The ArNS name to update--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
)
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 deploy
Or with on-demand payment:
DEPLOY_KEY=$(base64 -i wallet.json) pnpm deploy:on-demand
To automate deployments, set up a GitHub Actions workflow:
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 }}
# 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 format
permaweb-deploy/
├── src/
│ ├── commands/ # oclif commands
│ │ └── deploy.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 output
- 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: The ArNS Name must be passed so that the ANT Process can be resolved to update the 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-amount
limits to prevent unexpected costs - Secret Management: Keep your
DEPLOY_KEY
secret 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
- Error: "DEPLOY_KEY environment variable not set": Verify your base64 encoded wallet is set as the
DEPLOY_KEY
environment 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-demand
with--max-token-amount
to 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 (
ario
with Arweave,base-eth
with Ethereum)
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
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
We use changesets for version management. When making changes:
pnpm changeset
Follow the prompts to describe your changes.
- @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
ISC
NickJ202