Bulk Link Operations
Purpose and Scope
Bulk link operations are the parts of Dub that let a workspace act on many links as a single task instead of sending one request or performing one dashboard edit per link. In product terms, they cover API-level bulk create, update, delete, and count workflows, and they sit next to import workflows that notify users when large batches have succeeded or failed. This page focuses on the repository entry points supplied for those behaviors: the Links OpenAPI path assembly and the email templates that report link-import outcomes. Sources: apps/web/lib/openapi/links/index.ts, packages/email/src/templates/links-imported.tsx, packages/email/src/templates/links-import-errors.tsx
Dub treats links as a primary resource, so bulk operations are not a separate product area; they are an efficiency layer over link management. The public docs describe bulk creation as useful when many links must be created without multiple API calls, and they identify update and delete as similar multi-link operations. The source confirms that these operations are exposed under the same Links API family as single-link create, list, retrieve, update, delete, and upsert operations, which keeps generated API documentation and client SDKs organized around one link resource model.
Relevant Source Files
apps/web/lib/openapi/links/index.ts- Assembles the Links OpenAPI path object and maps/links/bulktopost,patch, anddeleteoperations while also registering/links/countfor count retrieval.packages/email/src/templates/links-imported.tsx- Defines the success notification sent after importing many links from providers such as Bitly, Short.io, Rebrandly, or CSV, including workspace, domain, count, and recently created link details.packages/email/src/templates/links-import-errors.tsx- Defines the error notification for failed imported links, including a capped error list, displayed link identifiers, and workspace context.
System-to-Code Mapping
The central repository mapping for bulk link behavior is the exported linksPaths object. It imports separate operation modules such as bulkCreateLinks, bulkUpdateLinks, and bulkDeleteLinks, then mounts them together at the /links/bulk path with HTTP verbs that match the intended action. In the same object, /links/count is registered as a get operation. That means count retrieval is part of the Links API surface, but it is represented as a read endpoint rather than as another verb on /links/bulk. Sources: apps/web/lib/openapi/links/index.ts
| Concern | Route or component | Source-backed role |
|---|---|---|
| Bulk create | POST /links/bulk | Registered in the Links OpenAPI path object as the bulk creation operation. |
| Bulk update | PATCH /links/bulk | Registered beside bulk create as the multi-link update operation. |
| Bulk delete | DELETE /links/bulk | Registered beside bulk create and update as the multi-link removal operation. |
| Count links | GET /links/count | Registered as a Links API count endpoint, useful for list and bulk-management workflows. |
| Import success notification | LinksImported | Email template summarizing how many links were imported and where they landed. |
| Import error notification | LinksImportErrors | Email template listing failed imported links and their error messages. |
The import emails show how batch link workflows continue after the API or background job has processed input. LinksImported accepts an email, an import provider, a numeric count, a list of recently created links, workspace identity, workspace slug, and the domains affected by the import. Its rendered message says the links were imported into a Dub workspace and displays formatted links using linkConstructor. This matters for bulk operations because users need a reliable completion signal after a large import, especially when the initiating action may have happened from a CSV or third-party provider rather than a single form submission. Sources: packages/email/src/templates/links-imported.tsx
The failure template provides the complementary operational signal. LinksImportErrors accepts errorLinks, each with a domain, key, and error, then displays a table of failed links. The source defines MAX_ERROR_LINKS = 20, slices the rendered list to that cap, and adds an overflow message when more errors exist. That is an important design detail for bulk operations: error reporting must be useful without producing an unreadable email. The template also asks the user to reply for additional help with CSV import, which frames failures as recoverable support cases rather than silent batch loss. Sources: packages/email/src/templates/links-import-errors.tsx
API Components
The compact public API shape for bulk link work is straightforward: create, update, and delete share /links/bulk, while counts use /links/count. The OpenAPI path file does not contain the full request schemas in the supplied snippet, but it does show the route family and verb mapping that generated API reference pages and SDKs depend on. In the official documentation, bulk create is described as creating up to 100 links for the authenticated workspace, and SDK examples call methods such as dub.links.createMany with an array of link creation inputs. Sources: apps/web/lib/openapi/links/index.ts
| API operation | HTTP method and path | Reader task |
|---|---|---|
| Bulk create links | POST /links/bulk | Submit multiple link creation inputs in one API request. |
| Bulk update links | PATCH /links/bulk | Apply link changes across multiple existing links. |
| Bulk delete links | DELETE /links/bulk | Remove multiple links in one request. |
| Get links count | GET /links/count | Retrieve a count for link-management, filtering, or pagination experiences. |
import { Dub } from "dub";
const dub = new Dub({
token: process.env.DUB_API_KEY,
});
const result = await dub.links.createMany([
{ url: "https://google.com" },
{ url: "https://google.uk" },
]);When implementing against these endpoints, treat bulk operations as workspace-scoped link mutations. Authentication and workspace selection are prerequisites in the public API, while the route organization keeps the resource noun stable: links remain links whether the caller modifies one link or many. The public docs also call out a practical constraint for bulk creation: webhook events are not triggered for bulk link creation, and custom link previews are not supported there. Those limits should influence integration design; if a downstream workflow depends on per-link webhooks or preview customization, a caller may need to choose single-link creation or run a follow-up process.
Execution Flow
A typical bulk-create API flow begins with a caller constructing an array of link inputs and sending it to the Links API. The API documentation and SDK examples put that behind a high-level client method, while the repository path assembly ensures the generated OpenAPI surface has a concrete POST /links/bulk entry. After the request, the caller should treat the response as the authoritative batch result. For imports, the processing system can also communicate completion through email, using the success template to provide total count, workspace link, domains, and a preview list of created links. Sources: apps/web/lib/openapi/links/index.ts, packages/email/src/templates/links-imported.tsx
Bulk update and bulk delete follow the same conceptual pattern, but their purpose is operational maintenance rather than creation. The dashboard help text describes selecting multiple links and applying actions such as tagging, moving to a folder, toggling conversion tracking, archiving, or deleting. The source path registration supports the API side of that same mental model by exposing PATCH /links/bulk and DELETE /links/bulk. Even when dashboard and API code paths differ internally, the developer-facing contract stays coherent: use the bulk route when the unit of work is a set of links rather than one link.
Failure handling is especially important for imports and other high-volume workflows. The error email does not merely say that a batch failed; it gives the user a bounded list of link identifiers and error strings so the next action is visible. Because the displayed link uses the domain and key, the user can recognize the intended short URL rather than an internal database identifier. The hard cap of 20 displayed errors is a user-experience guardrail that keeps the notification readable while still indicating how many additional failures occurred. Sources: packages/email/src/templates/links-import-errors.tsx
Implementation Details
The OpenAPI path file is deliberately small, which is a useful architecture signal. Instead of embedding each operation definition inline, it imports operation modules and composes the final ZodOpenApiPathsObject. That keeps the Links API reference modular: individual files can own schema, parameters, response details, and operation metadata, while links/index.ts owns the public path table. For anyone adding another bulk operation, the important repository step is not only implementing the operation module, but also registering it in this path object so generated documentation and clients can discover it. Sources: apps/web/lib/openapi/links/index.ts
The email templates are React Email components rather than plain strings. They import primitives such as Html, Head, Preview, Tailwind, Container, Section, Row, Column, Text, and Link, then compose a transactional message with Dub branding and a footer. They also reuse utility functions from @dub/utils, including linkConstructor, pluralize, timeAgo, and truncate. This keeps batch notifications consistent with the rest of the product while avoiding duplicate link-formatting logic inside the email package. Sources: packages/email/src/templates/links-imported.tsx, packages/email/src/templates/links-import-errors.tsx
For large link sets, small presentation details become operationally important. The success email formats count with Intl.NumberFormat("en-us"), pluralizes the affected domain label, links directly to https://app.dub.co/${workspaceSlug}, and conditionally renders a list only when link previews are available. The error email similarly formats the number of failures, truncates long pretty links to 40 characters, and suppresses hydration warnings around rendered values that may differ between server and client timing. These are implementation choices aimed at making bulk workflows understandable after the fact, not just executable at request time.
Practical Guidance and Next Steps
Use bulk creation when the caller already has many link destinations and wants a single API request. Use bulk update when the caller needs to apply the same management change across selected links, and use bulk delete when a set of links should be removed together. Use /links/count as a supporting read operation for dashboards, filters, and operational checks before or after a batch action. For CSV or third-party imports, plan for asynchronous user communication: successful imports should summarize the result, and partial failures should expose enough detail to repair the input file or retry safely.
Next, read links-api-bulk-count for the generated API-reference view of these endpoints, manage-links for single-link lifecycle tasks, and import-links for the CSV/provider import workflow. If you are building a product integration, also review authentication and rate-limit pages before sending large batches, because bulk operations reduce request count but still need the same workspace authorization and operational safeguards as the rest of the Dub API.