Mastering Self-Hosted Convex: A Complete Deployment Guide

Stop struggling with custom scripts and learn the professional way to deploy Convex functions to your own server using the official CLI.

JooklloJun 10, 20264 min read

Originally published on DEV Community by Jookllo. Read on the original site


title: "Mastering Self-Hosted Convex: A Complete Deployment Guide" published: true description: "Stop struggling with custom scripts and learn the professional way to deploy Convex functions to your own server using the official CLI." tags: "convex, selfhosted, tutorial"

cover_image: https://www.convex.dev/_next/image?url=%2F_next%2Fstatic%2Fmedia%2FlogoColor.167xlrvlsjp8k.svg&w=384&q=75

Use a ratio of 100:42 for best results.

published_at: 2026-06-11 02:45 +0000


Mastering Self-Hosted Convex: A Complete Deployment Guide

So, you've decided to take control of your data and self-host Convex. Great choice! But if you've tried pushing your functions to a local or private server, you might have run into cryptic errors about "Relative import paths" or "Missing modules."

The secret? You don't need custom deployment scripts. In fact, you shouldn't use them. The official Convex CLI is actually powerful enough to handle self-hosted deployments perfectly—if you know which buttons to press.

In this guide, I’ll show you exactly how to configure your project and deploy your functions like a pro.


1. Before You Start

Before we dive into the code, make sure you have the following ready:

  • Your Convex Instance: Whether you're using Dokploy, Docker, or a raw VPS, your backend should be up and running.
  • The Admin Key: You'll need the master key for your server.
    • Tip: If you're using Dokploy, you can usually generate this by running ./generate_admin_key.sh inside your backend container's terminal.
  • The CLI: Make sure you have the latest version of Convex installed locally:
    npm install convex
    

2. Preparing Your Project

For a smooth deployment, your convex/ folder needs to be a bit more "independent."

Step 1: Give Convex its own Identity

Create a package.json inside your convex/ directory. This ensures the CLI knows exactly which dependencies to bundle when it prepares your code for the server.

{
  "name": "my-convex-backend",
  "private": true,
  "type": "module",
  "dependencies": {
    "convex": "^1.16.0",
    "typescript": "^5.0.0"
  }
}

Step 2: Fix your Config

Ensure your convex/convex.config.ts is using the modern defineApp export. The server expects this structure to understand your app's layout.

import { defineApp } from "convex/server";

export default defineApp();

3. The Magic Environment Variables

The Convex CLI is "Cloud-first" by default, but we can tell it to target our own server by setting two specific environment variables.

VariableWhat it does
CONVEX_SELF_HOSTED_URLPoints the CLI to your backend URL (e.g., https://api.myapp.com).
CONVEX_SELF_HOSTED_ADMIN_KEYYour secret key. Crucial: It must include the `convex-self-hosted

4. The Big Moment: Deploying

Now, let's push your code. We're going to use the official deploy command.

Run this from your root or convex directory:

CONVEX_SELF_HOSTED_URL="https://your-api-url.com" \
CONVEX_SELF_HOSTED_ADMIN_KEY="convex-self-hosted|your-key-here" \
npx convex deploy --typecheck disable

Why this works where other scripts fail:

When you use a custom fetch script to send files, you're just sending raw text. The server has no idea where convex/server is.

The CLI is smarter. It uses esbuild to "bundle" your code into a single, self-contained JavaScript package. It finds all your imports and bakes them right into the file so the server can run them instantly.


5. Pro Tip: Automate Everything

Don't type those long variables every time. Add a script to your convex/package.json:

"scripts": {
  "deploy": "CONVEX_SELF_HOSTED_URL=... CONVEX_SELF_HOSTED_ADMIN_KEY=... npx convex deploy --typecheck disable"
}

Now, all it takes is a simple:

npm run deploy

Troubleshooting common "Gotchas"

"Relative import path 'convex/server' not found"

If you see this, you likely bypassed the CLI. Always use npx convex deploy so the bundler can do its job!

"BadAdminKey"

Double-check your key. Most people forget the convex-self-hosted| prefix. Without it, the server will reject your request every time.

Missing _generated files in your frontend

Run npx convex codegen while your CONVEX_SELF_HOSTED_URL is set to update your local TypeScript types to match what you just deployed.


Happy hosting! Your Convex backend is now truly yours.

Originally published on DEV Community by Jookllo. Read on the original site

You might also like