Self-hosting
Droppie is fully open source (MIT) and designed to run anywhere. The app is client-side — wallets sign everything, trees are built in the browser — so "self-hosting" is mostly serving static-ish Next.js pages plus one optional pinning endpoint.
Requirements
- Node.js >= 20 (we build with 22 — see
.nvmrc) - pnpm 9 (
corepack enablegives you the right version) - Foundry — only if you're hacking on the contracts themselves
Clone and build
git clone https://github.com/droppie-io/droppie-monorepo.git
cd droppie-monorepo
pnpm install
pnpm build # turbo builds sdk → web + docs
The monorepo layout:
droppie-monorepo/
├── apps/
│ ├── web/ # Next.js app — landing, dashboard, create, claim
│ └── docs/ # this docs site (Docusaurus)
├── packages/
│ ├── contracts/ # Foundry — DroppieDrop, DroppieERC20
│ └── sdk/ # @droppie/sdk
Run things locally:
pnpm --filter web dev # app on http://localhost:3000
pnpm --filter docs start # docs on http://localhost:3001
Environment variables
Copy .env.example to apps/web/.env.local and fill in what you need. Every variable is optional — the app degrades gracefully without them:
| Variable | Required | Fallback behavior when unset |
|---|---|---|
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID | No | Falls back to a dev placeholder ("droppie-dev"). Injected wallets (MetaMask, Rabby, …) work fine; WalletConnect QR pairing to mobile wallets won't. Get a free ID at dashboard.reown.com. |
NEXT_PUBLIC_DOCS_URL | No | The app's navbar/footer "Docs" links fall back to https://docs.droppie.notcool.in. Point it at your own deployment of this docs site if you host it yourself. |
PINATA_JWT | No | The /api/pin endpoint returns 501 with { "fallback": "download" }, and the create wizard offers the distribution JSON as a download instead of pinning to IPFS. Host the file on any HTTPS URL and use that as the drop's metadataURI. Get a JWT at pinata.cloud. |
NEXT_PUBLIC_ variables are baked in at build time — rebuild after changing them.
Docker
The repo root ships a Dockerfile that builds the web app as a Next.js standalone output — a small, self-contained image.
NEXT_PUBLIC_* variables are inlined into the client bundle at build time, so pass them as --build-args — setting them with docker run -e has no effect on an already-built image. Only server-side variables like PINATA_JWT are read at runtime:
# from the repo root — NEXT_PUBLIC_* vars are baked in at build time
docker build \
--build-arg NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=your_project_id \
-t droppie-web .
# PINATA_JWT is server-side, so a runtime -e works for it
docker run -p 3000:3000 -e PINATA_JWT=your_pinata_jwt droppie-web
NEXT_PUBLIC_DOCS_URL works the same way (--build-arg NEXT_PUBLIC_DOCS_URL=…) if you host this docs site yourself. Or with compose, using the repo's docker-compose.yml (which passes the build args for you, pointing the app's "Docs" link at the bundled docs container):
docker compose up -d --build
Environment variables come from your shell or a local .env file next to the compose file. The app listens on port 3000; put your reverse proxy of choice (Caddy, nginx, Traefik) in front for TLS.
The compose file also starts a local Anvil chain on :8545 (chain id 31337) — a handy sandbox for a full local demo. Add it to your wallet, fund your address with cast, and create tokens and drops from the app UI exactly like on any other chain.
This docs site builds to plain static files — pnpm --filter docs build outputs apps/docs/build/, which any static host (Netlify, Vercel, GitHub Pages, an S3 bucket) can serve as-is.
Contracts — nothing to pre-deploy
Droppie is factoryless: the app ships the contracts' creation bytecode inside @droppie/sdk, and every user deploys their own DroppieDrop / DroppieERC20 from their wallet. There are no hosted contracts, no addresses to configure, and no per-chain deployment step — a self-hosted Droppie works on every configured chain out of the box.
Two customizations you can make:
- Add a chain. Add its id and display metadata to
SUPPORTED_CHAINS/CHAIN_INFOinpackages/sdk/src/addresses.ts, wire it into the wagmi chain config inapps/web, and rebuild. Since users deploy their own contracts, the new chain is fully functional immediately. - Modify the contracts. Edit
packages/contracts/src, runforge build && forge test, regenerate thepackages/contracts/abi/*.jsonartifacts (the command is documented in the contracts package README), copy the newbytecodefields intopackages/sdk/src/bytecode.ts, and rebuild:
pnpm --filter @droppie/sdk build # its tests fail if bytecode drifts from the artifacts
pnpm --filter web build
Production checklist
- Set
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID(own the WalletConnect pairing experience) - Set
PINATA_JWTor plan to host distribution JSONs yourself - TLS-terminating reverse proxy in front of the container
- If you modified the contracts: regenerate the artifacts and SDK bytecode together
-
forge testand the CI suite pass on your commit