Self-Hosting
Purpose and Scope
Self-hosting Dub means running the open-source link attribution platform on infrastructure that you control instead of relying only on the hosted Dub service. The official self-hosting guide frames this path as a way to gain greater control over data and design, while still using the same product concepts: short links, conversion tracking, and affiliate-program workflows. In the repository, the self-hosting entry point is not a separate application; it is the monorepo itself, with the web app supported by shared packages, build scripts, and operational integrations.
The root package declares the repository as a private dub-monorepo licensed under AGPL-3.0-or-later, which is important for self-hosters who modify or expose the software over a network. It also establishes pnpm@9.15.9 as the package manager and uses Turborepo scripts such as dev, build, lint, clean, and test to coordinate work across apps and packages. For a self-hosted deployment, these scripts are the source-level control plane for preparing the codebase, validating changes, and building the packages that the web app depends on.
Sources: package.json
Relevant Source Files
package.json- Defines the monorepo name, AGPL license posture, package manager version, Turborepo-backed scripts, and package publishing commands that shape local and deployment workflows.packages/cli/src/index.ts- Defines the executabledubcommand and registers login, config, domains, shorten, and links subcommands for API-oriented operational workflows.packages/email/src/index.ts- Provides the email sending abstraction, choosing Resend when configured and falling back to SMTP through Nodemailer when SMTP environment variables exist.packages/ui/src/index.tsx- Re-exports the shared UI component library, styles, hooks, icons, layout pieces, and content utilities consumed by Dub surfaces.packages/utils/src/index.ts- Re-exports shared constants and functions that centralize common utility behavior across the repository.packages/cli/package.json- Describes the published CLI package, itsdubbinary, build scripts, runtime dependencies, and package metadata.
Self-Hosting Entry Point
A practical self-hosting path begins with cloning the Dub repository and installing dependencies with pnpm, matching the official guide’s first local setup steps. After that, the root scripts become the primary interface for working with the monorepo: pnpm dev runs turbo dev, pnpm build runs turbo build, and pnpm build:packages builds only packages under packages/**. The repository is organized so the hosted product and self-hosted product share code, which reduces the chance that self-hosting becomes a separate, stale distribution.
git clone https://github.com/dubinc/dub.git
cd dub
pnpm i
pnpm devFor operators, the distinction between local setup and production deployment is mainly infrastructure configuration. The official docs list external services such as Tinybird for analytics, Upstash for Redis, PlanetScale for the database, Vercel for deployment, and Cloudflare or AWS for domain and edge infrastructure. The supplied source files do not enumerate every environment variable, but they do show the monorepo-level contract: install with the declared package manager, run Turborepo scripts from the root, and treat shared packages as part of the application build rather than optional add-ons.
Sources: package.json
Core Runtime Packages
The shared package structure matters because self-hosting is not only about starting a Next.js app; it is about carrying the supporting runtime contracts with it. The @dub/ui entry point imports styles.css and re-exports component families such as buttons, forms, inputs, modals, tables, pagination controls, status badges, popovers, sheets, charts, and layout primitives. That means a self-hosted UI build depends on the package’s styles and component exports being available wherever the web application is compiled.
The utilities package is intentionally thin at its public boundary: packages/utils/src/index.ts re-exports constants and functions. That kind of boundary is useful in a self-hosted installation because callers can import shared constants and helpers from one stable package entry point instead of reaching into internal files. It also signals where cross-cutting behavior belongs when adapting Dub for an organization-specific deployment: prefer shared package exports over duplicating constants or utility logic inside deployment-specific code.
Email delivery is a concrete example of a self-hosting concern that is handled through a package-level abstraction. The email package exports sendEmail and sendBatchEmail. Both prefer Resend when the resend client is configured; otherwise they check whether SMTP_HOST and SMTP_PORT are present and fall back to Nodemailer. If neither provider is configured, the implementation logs that no email service is available, and batch email returns a neutral { data: null, error: null } response. This gives self-hosters two supported email paths without changing callers.
Sources: packages/ui/src/index.tsx, packages/utils/src/index.ts, packages/email/src/index.ts
CLI for Self-Hosted Operations
The CLI is a separate published package named dub-cli, but it is maintained inside the same repository. Its package metadata exposes a global dub binary from ./dist/index.js, marks the package as ESM with type: module, and builds with tsup. Runtime dependencies include commander for command routing, configstore for local configuration storage, dub for API access, OAuth and browser-opening helpers, prompts, and Zod. In self-hosted or hybrid environments, this CLI is the command-line face of Dub’s API workflows rather than a replacement for the web app.
At runtime, packages/cli/src/index.ts creates a Commander program named dub, describes it as a CLI for shortening links with the Dub API, wires version output, and registers five command groups: login, config, domains, shorten, and links. These command names are the main operational primitives visible from the entry point. They map to common self-hosting tasks such as authenticating, configuring the CLI, managing domains, creating shortened URLs, and working with existing links through API-backed commands.
pnpm build:packages
cd packages/cli
pnpm build
node dist/index.js --versionSources: packages/cli/package.json, packages/cli/src/index.ts
System-to-Code Mapping
| Self-hosting concern | Repository surface | Source-backed behavior |
|---|---|---|
| Monorepo orchestration | package.json | Uses Turborepo scripts for build, dev, lint, clean, and test; declares pnpm@9.15.9. |
| License posture | package.json | Declares AGPL-3.0-or-later at the repository root. |
| CLI operations | packages/cli/src/index.ts | Registers login, config, domains, shorten, and links under the dub command. |
| CLI packaging | packages/cli/package.json | Publishes the dub binary from dist/index.js and builds with tsup. |
| Email delivery | packages/email/src/index.ts | Sends through Resend when configured, otherwise uses SMTP when SMTP_HOST and SMTP_PORT exist. |
| Shared UI | packages/ui/src/index.tsx | Imports shared styles and re-exports UI components, hooks, icons, layout, content, and misc utilities. |
| Shared utilities | packages/utils/src/index.ts | Exposes package-level constants and functions exports. |
This mapping is the quickest way to decide where to look when adapting a self-hosted instance. Deployment mechanics and service provisioning live outside these package entry points, but the local source contracts are visible here. If a change affects product rendering, begin with the web app and the exported UI package. If it affects outbound notifications, inspect the email sender abstraction and configure either Resend or SMTP. If it affects command-line administration, build and test the CLI package and its registered command groups.
Sources: package.json, packages/cli/src/index.ts, packages/email/src/index.ts, packages/ui/src/index.tsx, packages/utils/src/index.ts, packages/cli/package.json
Implementation Details and Next Steps
When preparing a self-hosted deployment, keep repository-level and package-level responsibilities separate. The root workspace scripts should remain the canonical way to build and validate the monorepo, while package entry points should remain stable public boundaries for shared UI, utilities, email, and CLI behavior. This helps upgrades stay manageable: changes can be reviewed at the package boundary instead of being scattered across deployment scripts and application code. It also aligns self-hosting with the same monorepo workflow used for product development.
A recommended next pass is to pair this source map with the full self-hosting guide and then inventory the environment variables required by the web app and infrastructure providers. Configure email first enough to support account and operational notifications, confirm analytics infrastructure separately, and run root build or test scripts before deploying. For deeper implementation context, continue with the local development, monorepo tech stack, CLI reference, email package, and Tinybird analytics pages.
Sources: package.json, packages/email/src/index.ts, packages/cli/package.json