Host it yourself

Run your own Drop on Cloudflare, Vercel, Netlify, Deno Deploy, or a VPS.

Start with the button for your host. You still supply GitHub sign-in and your admin user id. The steps below cover those values and the database.

Sign-in and admins

Drop signs in with GitHub. You can also reuse an existing GitHub oauth2-proxy. For native sign-in, Create a GitHub OAuth app with:

  • Homepage URL: https://<your-domain>
  • Authorization callback URL: https://<your-domain>/api/auth/callback/github

Then give the deployment these settings. Each host page says where they go.

VariableWhat it is
GITHUB_CLIENT_IDYour GitHub OAuth app's client ID.
GITHUB_CLIENT_SECRETA client secret from the same app.
BETTER_AUTH_SECRETSigns sessions and agent tokens. One per deployment: openssl rand -base64 32
DROP_ADMINSGitHub user ids that join as Admin, comma-separated: gh api users/<login> --jq .id

By default, anyone with a GitHub account can sign in and joins as a Member. Set DROP_GITHUB_ORG to require active organization membership for publishing and viewing, including shared links and MCP. GitHub sign-in then requests read:org. The accounts in DROP_ADMINS join as Admin, and admins change roles on the Members page. To use another sign-in provider, change the Better Auth options in server/auth.ts.

RoleWhat they can do
AdminEverything, plus members and settings.
EditorEdit and share any drop in the workspace.
MemberCreate, share, and comment on their own drops.

Database and migrations

Docker and VPS builds default to local SQLite on persistent disk. The other hosts use separate Cloudflare D1 databases, with D1's HTTP API outside Cloudflare. The same migrations in server/databases/migrations apply to all of them:

For a deployment that uses D1 outside Cloudflare, create it from a machine with Node.js:

npx wrangler login
npx wrangler d1 create my-drop

Copy its id and name, your Cloudflare account id, and an account API token with Account, D1, Edit permission into the host's settings. Limit the token to your account.

From your cloned repository, pnpm db:migrate:d1 needs CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_API_TOKEN, and CLOUDFLARE_D1_DATABASE_ID in its environment. It records migrations in d1_migrations and skips those already applied.

  • Cloudflare's button runs pnpm run deploy, which applies migrations by the DB binding. Existing Workers Builds using npx wrangler deploy still need pnpm db:migrate:remote after schema changes.
  • Vercel and Netlify run pnpm db:migrate:d1 after building, before publishing.
  • Deno runs it as a pre-deploy command. Docker Compose uses Drizzle for SQLite, or this command for an explicit D1 build, before starting Drop.

Use a separate D1 database for previews, or disable preview deployments. A build with production D1 credentials migrates that database.

After you change the schema in server/databases/, pnpm db:generate writes the next migration.

Pick a host

Cloudflare has everything Drop uses in one account. VPS builds can keep all data on local disk; the serverless hosts use D1 over HTTP with a separate database per deployment. Every host but Cloudflare renders code images as SVG only.

HostDatabaseFilesRate limitsCode images
CloudflareD1R2Workers rate limitingPNG and SVG
VercelD1 over HTTPVercel BlobPer instanceSVG
NetlifyD1 over HTTPNetlify BlobsPer instanceSVG
Deno DeployD1 over HTTPR2 S3 APIPer instanceSVG
VPSLocal SQLite or D1Local diskIn memorySVG

Choose the host at build time

DROP_HOST explicitly picks the host when you build. Otherwise Drop detects NITRO_PRESET or SERVER_PRESET, then Vercel, Netlify, or Deno environment markers. A local DROP_DATABASE_URL selects VPS when no host is selected. With no signal, it builds for Cloudflare. Docker always selects VPS.

DROP_HOST=vercel pnpm build   # explicit override: cloudflare, vercel, netlify, deno, or vps

Use DROP_DATABASE=sqlite or DROP_DATABASE=d1 to choose the database at build time. SQLite requires the VPS preset and persistent disk. An existing D1 database id keeps a VPS build on D1. Rebuild to change drivers and migrate data separately.

nuxt.config.ts maps each host to its ViteHub preset and drivers: the database, file storage, rate limiting, and the job that deletes expired code images. Your code doesn't change; ViteHub swaps the drivers behind vite-hub/database, vite-hub/blob, and the rest.

What changes between hosts

  • Code images. PNG is a Cloudflare Browser Run screenshot of the SVG, so only Cloudflare has it. Elsewhere create_code_image returns SVG, and asking for PNG fails with a clear error.
  • Rate limits. Cloudflare uses its rate limiting binding. Other hosts count in memory, per server instance, so limits are looser on serverless hosts that run many instances.
  • Expired code images. An hourly job deletes them on Cloudflare, Netlify, and a VPS. Vercel runs cleanup daily so it works on Hobby. Deno Deploy has none; expired images stop being served but stay in the bucket.
  • Caching. Rendered Markdown and the file count are cached in Workers KV on Cloudflare, and in memory elsewhere.

Check a deployment

The smoke test checks the public pages, the OAuth discovery documents, that /mcp asks agents to sign in, and the skills index:

DROP_URL=https://<your-domain> pnpm test:e2e:deployed

Add DROP_TOKEN=<an MCP access token> to also run the signed-in flow: uploads, sharing, and MCP tools.

Develop locally

pnpm install
pnpm db:migrate   # once, and after schema changes
pnpm dev          # http://localhost:3000

Local dev runs against a local D1 and keeps files in .vitehub/data/blob. It has no GitHub app, so it also allows email and password sign-in: open /?signin=1.