Configuration
Complete guide to configuring Etch.
Environment Variables
Required
| Variable | Description | Example |
|---|---|---|
JWT_SECRET | Auth signing key (32+ chars) | random-32-character-string-here |
ETCH_WALLET_SECRET | Solana keypair for transactions | Base58 or JSON array |
DATABASE_URL | Postgres connection string | postgresql://... |
Solana
| Variable | Description | Default |
|---|---|---|
SOLANA_RPC_URL | RPC endpoint | https://api.mainnet-beta.solana.com |
SOLANA_CLUSTER | Network | mainnet-beta |
Use a paid RPC provider for production. Free endpoints have rate limits.
Job Queue (QStash)
| Variable | Description |
|---|---|
QSTASH_TOKEN | QStash API token |
QSTASH_CURRENT_SIGNING_KEY | Webhook verification |
QSTASH_NEXT_SIGNING_KEY | Key rotation |
Without QStash, jobs run synchronously in development.
Rate Limiting (Redis)
| Variable | Description |
|---|---|
UPSTASH_REDIS_REST_URL | Redis endpoint |
UPSTASH_REDIS_REST_TOKEN | Redis token |
Without Redis, rate limiting uses in-memory store (single-instance only).
Admin Portal
| Variable | Description | Default |
|---|---|---|
ADMIN_SECRET | Admin password (16+ chars) | Disabled |
CRON_SECRET | Cron job auth token | Disabled |
Metadata Storage
Choose one provider:
# Option 1: Pinata (recommended)
PINATA_JWT=your-pinata-jwt
# Option 2: NFT.Storage
NFT_STORAGE_KEY=your-nft-storage-key
# Option 3: Custom
METADATA_API_URL=https://your-api.com/upload
METADATA_API_KEY=your-keyMiscellaneous
| Variable | Description | Default |
|---|---|---|
LAUNCHES_PER_AGENT_PER_DAY | Rate limit | 1 |
JWT_EXPIRY | Token lifetime | 24h |
LOG_LEVEL | Logging verbosity | info |
NODE_ENV | Environment | development |
Wallet Setup
Generate a Keypair
solana-keygen new --outfile etch-wallet.jsonSet as Environment Variable
Option A: Base58
export ETCH_WALLET_SECRET=$(cat etch-wallet.json | solana-keygen pubkey -)
# Actually need the secret key, not pubkey. Use:
export ETCH_WALLET_SECRET=$(cat etch-wallet.json)Option B: JSON Array
export ETCH_WALLET_SECRET='[1,2,3,...,64]' # 64-byte arrayFund the Wallet
Devnet:
solana airdrop 2 $(solana-keygen pubkey etch-wallet.json) --url devnetMainnet: Transfer SOL from your wallet.
The Etch wallet pays transaction fees. Keep it funded with 0.5-1 SOL minimum.
Database Setup
Supabase (Recommended)
- Create project at supabase.com
- Go to Settings → Database
- Copy the connection string
- Set
DATABASE_URL
Run Migrations
cd packages/api
psql $DATABASE_URL -f db/migrations/0001_add_indexes.sql
psql $DATABASE_URL -f db/migrations/0002_add_dead_letter_queue.sqlOr use the Drizzle push command:
npm run db:pushVercel Deployment
Environment Variables
Add all variables in Vercel Dashboard → Settings → Environment Variables.
Cron Jobs
Etch includes vercel.json with cron configuration:
{
"crons": [
{
"path": "/api/cron/cleanup",
"schedule": "0 * * * *"
}
]
}This runs database cleanup every hour.
Security Headers
Automatically applied to /api/*:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=blockLocal Development
Quick Start
# Clone and install
git clone https://github.com/etch-dev/etch
cd etch
npm install
# Set up environment
cp packages/api/.env.example packages/api/.env.local
# Edit .env.local with your values
# Start development server
npm run devWithout External Services
For local development without QStash/Redis:
# .env.local
NODE_ENV=development
JWT_SECRET=dev-secret-at-least-32-characters
ETCH_WALLET_SECRET=[your-devnet-wallet-json]
SOLANA_RPC_URL=https://api.devnet.solana.com
SOLANA_CLUSTER=devnet
# Leave QStash/Redis empty for fallback modeJobs will run synchronously, rate limiting will use memory.
Health Check
Verify configuration:
curl https://etch.film.fun/api/healthResponse includes config status:
{
"status": "healthy",
"config": {
"jwtConfigured": true,
"walletConfigured": true,
"qstashAvailable": false,
"cluster": "devnet"
}
}