LinkDen
Self-Hosting

Vercel Deployment

Deploy the LinkDen web app on Vercel with the API running on Cloudflare Workers or another platform.

Vercel Deployment

Vercel is the company behind Next.js and provides an optimized hosting platform for Next.js applications. This guide covers deploying the LinkDen web app to Vercel while running the API on a separate platform (typically Cloudflare Workers).

Important: Split Architecture

Vercel hosts only the web app (Next.js frontend). The API server (Hono) must run separately because:

  • The Hono API uses Cloudflare Workers-specific APIs (D1 bindings, Workers runtime).
  • Vercel Functions use a different runtime and do not support D1.
  • LinkDen's API is a standalone Hono server, not a Next.js API route.
┌──────────────────┐     ┌────────────────────────┐     ┌──────────────┐
│  Vercel           │────▶│  Cloudflare Workers     │────▶│ Cloudflare D1│
│  (Next.js static  │     │  (Hono API server)      │     │ (SQLite DB)  │
│   export)         │     │  -- OR --               │     │              │
│                   │     │  Railway / Docker / etc. │     │              │
└──────────────────┘     └────────────────────────┘     └──────────────┘

Recommended API hosting options:

PlatformDatabaseBest For
Cloudflare WorkersD1Best performance, free tier
RailwaySQLite volumeSimple managed hosting
Docker (any VPS)SQLite fileFull control

See the respective guides for deploying the API: Cloudflare, Railway, or Docker.

Prerequisites

  1. A Vercel account (free Hobby plan is sufficient).
  2. The LinkDen repository on GitHub (Vercel connects directly to your GitHub repo).
  3. The API server already deployed and accessible at a public URL.
  4. Clerk API keys from clerk.com.

Step 1: Deploy the API First

Before setting up Vercel, deploy the API server using one of the supported platforms. You need the API's public URL for the web app's environment variables.

For example, if deploying the API on Cloudflare Workers:

# From the LinkDen repo root
pnpm cf:deploy

Note the Worker URL (e.g., https://linkden-api.your-subdomain.workers.dev).

Step 2: Import the Project to Vercel

  1. Log in to the Vercel dashboard.
  2. Click Add New > Project.
  3. Select Import Git Repository and choose the LinkDen repository.
  4. Vercel detects the monorepo structure.

Configure Build Settings

SettingValue
Framework PresetNext.js
Root Directoryapps/web
Build Commandcd ../.. && pnpm --filter @linkden/web build
Output Directoryout
Install Commandcd ../.. && pnpm install --frozen-lockfile

The output: "export" setting in next.config.ts tells Next.js to produce a static export, which Vercel serves as static files with its global CDN.

Alternative: Use Vercel's Monorepo Support

Vercel has built-in monorepo support. You can also configure via vercel.json in the repo root:

{
  "buildCommand": "pnpm --filter @linkden/web build",
  "installCommand": "pnpm install --frozen-lockfile",
  "outputDirectory": "apps/web/out",
  "framework": "nextjs"
}

Step 3: Configure Environment Variables

In the Vercel dashboard, go to your project's Settings > Environment Variables and add:

Required Variables

VariableValueEnvironment
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEYpk_live_...Production
CLERK_SECRET_KEYsk_live_...Production
NEXT_PUBLIC_API_URLhttps://api.yourdomain.comProduction
NEXT_PUBLIC_SITE_URLhttps://yourdomain.comProduction

Optional Variables

VariableValueEnvironment
NEXT_PUBLIC_SITE_NAMEMy LinksProduction
NEXT_PUBLIC_TURNSTILE_SITE_KEY0x...Production
NEXT_PUBLIC_CLERK_SIGN_IN_URL/sign-inProduction
NEXT_PUBLIC_CLERK_SIGN_UP_URL/sign-upProduction

Development Environment

For preview deployments (pull request previews), add development values:

VariableValueEnvironment
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEYpk_test_...Preview
CLERK_SECRET_KEYsk_test_...Preview
NEXT_PUBLIC_API_URLYour staging API URLPreview
NEXT_PUBLIC_SITE_URL(Vercel provides this automatically)Preview

Step 4: Deploy

Click Deploy. Vercel:

  1. Clones the repository.
  2. Installs dependencies with pnpm.
  3. Runs the Next.js build (which produces a static export in apps/web/out).
  4. Deploys the static files to Vercel's global edge network.

The first deploy takes 2-3 minutes. Subsequent deploys are faster due to caching.

Your site is live at https://your-project.vercel.app.

Step 5: Set Up a Custom Domain

  1. Go to your project's Settings > Domains.
  2. Enter your domain (e.g., yourdomain.com).
  3. Vercel shows the DNS records to add.

For Apex Domains

Add an A record at your DNS provider:

TypeNameTarget
A@76.76.21.21

For Subdomains

Add a CNAME record:

TypeNameTarget
CNAMElinkscname.vercel-dns.com

After DNS Setup

  • Vercel automatically provisions an SSL certificate.
  • Verify by visiting https://yourdomain.com.
  • Update NEXT_PUBLIC_SITE_URL in Vercel's environment variables to match your custom domain.
  • Update CORS_ORIGIN and APP_URL on the API server.
  • Redeploy for the URL change to take effect.

Using Both Vercel and Cloudflare DNS

If your domain uses Cloudflare DNS and you want to point it to Vercel:

  1. Add the CNAME record in Cloudflare DNS.
  2. Set the proxy status to DNS only (grey cloud) -- not proxied. Vercel needs direct DNS resolution for SSL provisioning.
  3. Alternatively, if you want Cloudflare's proxy (orange cloud), add your domain in Vercel and follow their guide for Cloudflare integration.

Step 6: Configure Clerk

Update your Clerk application settings:

  1. Go to the Clerk dashboard.
  2. Under Domains, add your Vercel production domain.
  3. If using preview deployments, add *.vercel.app as an allowed domain for development.

Automatic Deployments

Vercel automatically deploys when you push to your connected branch:

  • Production: Pushes to main trigger a production deployment.
  • Preview: Pull requests get a unique preview URL for testing.

Configuring Deployment Branches

By default, Vercel deploys the main branch to production. To change this:

  1. Go to Settings > Git.
  2. Change the Production Branch.

Skipping Deployments

To skip unnecessary builds when only non-web files change, add to vercel.json:

{
  "ignoreCommand": "git diff --quiet HEAD^ HEAD -- apps/web/ packages/ui/ packages/validators/"
}

This skips the build if no files in the web app or its dependencies changed.

Edge Functions Considerations

LinkDen's web app is a static export (output: "export" in next.config.ts), which means:

  • No server-side rendering (SSR): All pages are pre-rendered at build time.
  • No API routes: The Hono API runs separately.
  • No Edge Functions needed: The static export does not use Vercel's Edge or Serverless Functions.
  • No Middleware: Clerk middleware runs at build time only.

This makes the Vercel deployment very simple and cost-effective -- it is essentially static file hosting with a global CDN.

If you ever need SSR features (such as dynamic server-side rendering or API routes within the Next.js app), you would need to change output: "export" to output: "standalone" in next.config.ts. This is a significant architectural change and is not covered in this guide.

Performance Optimization

CDN and Caching

Vercel serves static assets from its global edge network. For optimal caching:

  • Static assets (_next/static/*) are automatically cached with long Cache-Control headers.
  • HTML pages are served with appropriate revalidation headers.

Image Optimization

Since the web app uses images.unoptimized: true in next.config.ts (required for static export), consider:

  • Optimizing images before uploading them to LinkDen.
  • Using external image optimization services.
  • Serving images via Cloudflare's Image Optimization if your images are on a Cloudflare-proxied domain.

Costs

Vercel pricing:

PlanCostIncludes
HobbyFree100 GB bandwidth, unlimited sites, automatic SSL
Pro$20/month per member1 TB bandwidth, advanced analytics, password protection
EnterpriseCustomSLA, SAML SSO, audit logs

For a static LinkDen site, the Hobby plan (free) is more than sufficient. The 100 GB bandwidth limit translates to millions of page views.

Total cost for Vercel + Cloudflare Workers stack:

  • Vercel Hobby: $0/month
  • Cloudflare Workers free tier: $0/month
  • Total: $0/month for most personal link pages

Troubleshooting

Build fails with "Cannot find module"

  • Ensure the Install Command runs from the monorepo root: cd ../.. && pnpm install --frozen-lockfile.
  • Check that pnpm-workspace.yaml includes the web app and its dependencies.

"NEXT_PUBLIC_API_URL is undefined"

  • NEXT_PUBLIC_* variables must be set before the build runs.
  • Verify the variables are added in Vercel's Environment Variables settings, not just locally.
  • Trigger a new deployment after adding variables (Vercel does not automatically redeploy).

CORS errors when calling the API

  • The API's CORS_ORIGIN must include the Vercel domain.
  • If using both *.vercel.app and a custom domain, add both to CORS_ORIGIN (comma-separated).

Custom domain shows "Invalid configuration"

  • Verify DNS records are correct.
  • If using Cloudflare DNS, set the proxy to DNS only (grey cloud).
  • Wait for DNS propagation and retry.

Preview deployments fail on Clerk auth

  • Clerk needs the preview deployment URL in its allowed domains.
  • Add *.vercel.app as an allowed domain in Clerk for development.
  • Use separate Clerk development keys for preview environments.

Static export does not include dynamic pages

  • The output: "export" mode pre-renders all pages at build time.
  • Dynamic routes like /[slug] need generateStaticParams() to define which paths to generate.
  • If a page is missing, check the build output for warnings about ungenerated routes.

On this page