bknd-deploy-hosting

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Deploy to Hosting

部署至托管平台

Deploy your Bknd application to various hosting platforms.
将你的Bknd应用部署至各类托管平台。

Prerequisites

前置条件

  • Working Bknd application locally
  • Schema defined and tested
  • Database provisioned (see
    bknd-database-provision
    )
  • Environment variables prepared (see
    bknd-env-config
    )
  • 本地可正常运行的Bknd应用
  • 已定义并测试完成的Schema
  • 已配置数据库(参考
    bknd-database-provision
  • 已准备好环境变量(参考
    bknd-env-config

When to Use UI Mode

何时使用UI模式

  • Cloudflare/Vercel dashboards for environment variables
  • Platform-specific deployment settings
  • Viewing deployment logs
  • 通过Cloudflare/Vercel控制台配置环境变量
  • 设置平台专属的部署参数
  • 查看部署日志

When to Use Code Mode

何时使用代码模式

  • All deployment configuration and commands
  • Adapter setup for target platform
  • CI/CD pipeline configuration
  • 所有部署配置与命令
  • 目标平台的适配器设置
  • CI/CD流水线配置

Platform Selection Guide

平台选择指南

PlatformBest ForDatabase OptionsCold Start
Cloudflare WorkersEdge, global low-latencyD1, Turso~0ms
Cloudflare PagesStatic + APID1, Turso~0ms
VercelNext.js appsTurso, Neon~200ms
Node.js/Bun VPSFull control, dedicatedAnyN/A
DockerContainerized, portableAnyN/A
AWS LambdaServerless, pay-per-useTurso, RDS~500ms
平台适用场景数据库选项冷启动
Cloudflare Workers边缘计算、全球低延迟D1, Turso~0ms
Cloudflare Pages静态站点+APID1, Turso~0ms
VercelNext.js应用Turso, Neon~200ms
Node.js/Bun VPS完全控制、专属服务器任意N/A
Docker容器化、可移植任意N/A
AWS Lambda无服务器、按使用付费Turso, RDS~500ms

Code Approach

代码部署方式

Cloudflare Workers

Cloudflare Workers

Step 1: Install Wrangler
bash
npm install -D wrangler
Step 2: Create
wrangler.toml
toml
name = "my-bknd-app"
main = "src/index.ts"
compatibility_date = "2024-01-01"

[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "your-d1-database-id"
步骤1:安装Wrangler
bash
npm install -D wrangler
步骤2:创建
wrangler.toml
toml
name = "my-bknd-app"
main = "src/index.ts"
compatibility_date = "2024-01-01"

[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "your-d1-database-id"

Optional: R2 for media storage

Optional: R2 for media storage

[[r2_buckets]] binding = "R2_BUCKET" bucket_name = "my-bucket"
[vars] ENVIRONMENT = "production"

**Step 3: Configure Adapter**

```typescript
// src/index.ts
import { hybrid, type CloudflareBkndConfig } from "bknd/adapter/cloudflare";
import { d1Sqlite } from "bknd/adapter/cloudflare";
import { em, entity, text } from "bknd";

const schema = em({
  posts: entity("posts", {
    title: text().required(),
  }),
});

export default hybrid<CloudflareBkndConfig>({
  app: (env) => ({
    connection: d1Sqlite({ binding: env.DB }),
    schema,
    isProduction: true,
    auth: {
      jwt: {
        secret: env.JWT_SECRET,
      },
    },
    config: {
      media: {
        enabled: true,
        adapter: {
          type: "r2",
          config: { bucket: env.R2_BUCKET },
        },
      },
    },
  }),
});
Step 4: Create D1 Database
bash
undefined
[[r2_buckets]] binding = "R2_BUCKET" bucket_name = "my-bucket"
[vars] ENVIRONMENT = "production"

**步骤3:配置适配器**

```typescript
// src/index.ts
import { hybrid, type CloudflareBkndConfig } from "bknd/adapter/cloudflare";
import { d1Sqlite } from "bknd/adapter/cloudflare";
import { em, entity, text } from "bknd";

const schema = em({
  posts: entity("posts", {
    title: text().required(),
  }),
});

export default hybrid<CloudflareBkndConfig>({
  app: (env) => ({
    connection: d1Sqlite({ binding: env.DB }),
    schema,
    isProduction: true,
    auth: {
      jwt: {
        secret: env.JWT_SECRET,
      },
    },
    config: {
      media: {
        enabled: true,
        adapter: {
          type: "r2",
          config: { bucket: env.R2_BUCKET },
        },
      },
    },
  }),
});
步骤4:创建D1数据库
bash
undefined

Create database

Create database

wrangler d1 create my-database
wrangler d1 create my-database

Copy the database_id to wrangler.toml

Copy the database_id to wrangler.toml


**Step 5: Set Secrets**

```bash
wrangler secret put JWT_SECRET

**步骤5:设置密钥**

```bash
wrangler secret put JWT_SECRET

Enter your secret (min 32 chars)

Enter your secret (min 32 chars)


**Step 6: Deploy**

```bash
wrangler deploy


**步骤6:部署**

```bash
wrangler deploy

Cloudflare Pages (with Functions)

Cloudflare Pages(搭配Functions)

Step 1: Create
functions/api/[[bknd]].ts
typescript
import { hybrid, type CloudflareBkndConfig } from "bknd/adapter/cloudflare";
import { d1Sqlite } from "bknd/adapter/cloudflare";
import schema from "../../bknd.config";

export const onRequest = hybrid<CloudflareBkndConfig>({
  app: (env) => ({
    connection: d1Sqlite({ binding: env.DB }),
    schema,
    isProduction: true,
    auth: {
      jwt: { secret: env.JWT_SECRET },
    },
  }),
});
Step 2: Configure Pages
In Cloudflare dashboard:
  1. Connect your git repository
  2. Set build command (if any)
  3. Add D1 binding under Settings > Functions > D1 Database Bindings
  4. Add environment variables under Settings > Environment Variables

步骤1:创建
functions/api/[[bknd]].ts
typescript
import { hybrid, type CloudflareBkndConfig } from "bknd/adapter/cloudflare";
import { d1Sqlite } from "bknd/adapter/cloudflare";
import schema from "../../bknd.config";

export const onRequest = hybrid<CloudflareBkndConfig>({
  app: (env) => ({
    connection: d1Sqlite({ binding: env.DB }),
    schema,
    isProduction: true,
    auth: {
      jwt: { secret: env.JWT_SECRET },
    },
  }),
});
步骤2:配置Pages
在Cloudflare控制台中:
  1. 连接你的Git仓库
  2. 设置构建命令(如有需要)
  3. 在「设置 > 函数 > D1数据库绑定」中添加D1绑定
  4. 在「设置 > 环境变量」中添加环境变量

Node.js / Bun (VPS)

Node.js / Bun(VPS)

Step 1: Create Production Entry
typescript
// index.ts
import { serve, type BunBkndConfig } from "bknd/adapter/bun";
// or for Node.js:
// import { serve } from "bknd/adapter/node";

const config: BunBkndConfig = {
  connection: {
    url: process.env.DB_URL!,
    authToken: process.env.DB_TOKEN,
  },
  isProduction: true,
  auth: {
    jwt: {
      secret: process.env.JWT_SECRET!,
      expires: "7d",
    },
  },
  config: {
    media: {
      enabled: true,
      adapter: {
        type: "s3",
        config: {
          bucket: process.env.S3_BUCKET!,
          region: process.env.S3_REGION!,
          accessKeyId: process.env.S3_ACCESS_KEY!,
          secretAccessKey: process.env.S3_SECRET_KEY!,
        },
      },
    },
    guard: {
      enabled: true,
    },
  },
};

serve(config);
Step 2: Set Environment Variables
bash
export DB_URL="libsql://your-db.turso.io"
export DB_TOKEN="your-turso-token"
export JWT_SECRET="your-32-char-minimum-secret"
export PORT=3000
Step 3: Run with Process Manager
bash
undefined
步骤1:创建生产环境入口文件
typescript
// index.ts
import { serve, type BunBkndConfig } from "bknd/adapter/bun";
// 若使用Node.js则改为:
// import { serve } from "bknd/adapter/node";

const config: BunBkndConfig = {
  connection: {
    url: process.env.DB_URL!,
    authToken: process.env.DB_TOKEN,
  },
  isProduction: true,
  auth: {
    jwt: {
      secret: process.env.JWT_SECRET!,
      expires: "7d",
    },
  },
  config: {
    media: {
      enabled: true,
      adapter: {
        type: "s3",
        config: {
          bucket: process.env.S3_BUCKET!,
          region: process.env.S3_REGION!,
          accessKeyId: process.env.S3_ACCESS_KEY!,
          secretAccessKey: process.env.S3_SECRET_KEY!,
        },
      },
    },
    guard: {
      enabled: true,
    },
  },
};

serve(config);
步骤2:设置环境变量
bash
export DB_URL="libsql://your-db.turso.io"
export DB_TOKEN="your-turso-token"
export JWT_SECRET="your-32-char-minimum-secret"
export PORT=3000
步骤3:使用进程管理器运行
bash
undefined

Using PM2

使用PM2

npm install -g pm2 pm2 start "bun run index.ts" --name bknd-app
npm install -g pm2 pm2 start "bun run index.ts" --name bknd-app

Or systemd (create /etc/systemd/system/bknd.service)

或使用systemd(创建/etc/systemd/system/bknd.service)


---

---

Docker

Docker

Step 1: Create
Dockerfile
dockerfile
FROM oven/bun:1.0-alpine

WORKDIR /app

COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile --production

COPY . .
步骤1:创建
Dockerfile
dockerfile
FROM oven/bun:1.0-alpine

WORKDIR /app

COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile --production

COPY . .

Create data directory for SQLite (if using file-based)

为SQLite创建数据目录(若使用文件型数据库)

RUN mkdir -p /app/data
ENV PORT=3000
EXPOSE 3000
CMD ["bun", "run", "index.ts"]

**Step 2: Create `docker-compose.yml`**

```yaml
version: "3.8"
services:
  bknd:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - bknd-data:/app/data
    environment:
      - DB_URL=file:/app/data/bknd.db
      - JWT_SECRET=${JWT_SECRET}
      - NODE_ENV=production
    restart: unless-stopped

volumes:
  bknd-data:
Step 3: Deploy
bash
undefined
RUN mkdir -p /app/data
ENV PORT=3000
EXPOSE 3000
CMD ["bun", "run", "index.ts"]

**步骤2:创建`docker-compose.yml`**

```yaml
version: "3.8"
services:
  bknd:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - bknd-data:/app/data
    environment:
      - DB_URL=file:/app/data/bknd.db
      - JWT_SECRET=${JWT_SECRET}
      - NODE_ENV=production
    restart: unless-stopped

volumes:
  bknd-data:
步骤3:部署
bash
undefined

Build and run

构建并运行

docker compose up -d
docker compose up -d

View logs

查看日志

docker compose logs -f bknd

---
docker compose logs -f bknd

---

Vercel (Next.js)

Vercel(Next.js)

Step 1: Create API Route
typescript
// app/api/bknd/[[...bknd]]/route.ts
export { GET, POST, PUT, DELETE, PATCH } from "bknd/adapter/nextjs";
Step 2: Create
bknd.config.ts
typescript
import type { NextjsBkndConfig } from "bknd/adapter/nextjs";
import { em, entity, text } from "bknd";

const schema = em({
  posts: entity("posts", {
    title: text().required(),
  }),
});

type Database = (typeof schema)["DB"];
declare module "bknd" {
  interface DB extends Database {}
}

export default {
  app: (env) => ({
    connection: {
      url: env.DB_URL,
      authToken: env.DB_TOKEN,
    },
    schema,
    isProduction: env.NODE_ENV === "production",
    auth: {
      jwt: { secret: env.JWT_SECRET },
    },
  }),
} satisfies NextjsBkndConfig;
Step 3: Set Vercel Environment Variables
In Vercel dashboard or CLI:
bash
vercel env add DB_URL
vercel env add DB_TOKEN
vercel env add JWT_SECRET
Step 4: Deploy
bash
vercel deploy --prod

步骤1:创建API路由
typescript
// app/api/bknd/[[...bknd]]/route.ts
export { GET, POST, PUT, DELETE, PATCH } from "bknd/adapter/nextjs";
步骤2:创建
bknd.config.ts
typescript
import type { NextjsBkndConfig } from "bknd/adapter/nextjs";
import { em, entity, text } from "bknd";

const schema = em({
  posts: entity("posts", {
    title: text().required(),
  }),
});

type Database = (typeof schema)["DB"];
declare module "bknd" {
  interface DB extends Database {}
}

export default {
  app: (env) => ({
    connection: {
      url: env.DB_URL,
      authToken: env.DB_TOKEN,
    },
    schema,
    isProduction: env.NODE_ENV === "production",
    auth: {
      jwt: { secret: env.JWT_SECRET },
    },
  }),
} satisfies NextjsBkndConfig;
步骤3:设置Vercel环境变量
在Vercel控制台或CLI中执行:
bash
vercel env add DB_URL
vercel env add DB_TOKEN
vercel env add JWT_SECRET
步骤4:部署
bash
vercel deploy --prod

AWS Lambda

AWS Lambda

Step 1: Install Dependencies
bash
npm install -D serverless serverless-esbuild
Step 2: Create
handler.ts
typescript
import { createHandler } from "bknd/adapter/aws";

export const handler = createHandler({
  connection: {
    url: process.env.DB_URL!,
    authToken: process.env.DB_TOKEN,
  },
  isProduction: true,
  auth: {
    jwt: { secret: process.env.JWT_SECRET! },
  },
});
Step 3: Create
serverless.yml
yaml
service: bknd-api

provider:
  name: aws
  runtime: nodejs20.x
  region: us-east-1
  environment:
    DB_URL: ${env:DB_URL}
    DB_TOKEN: ${env:DB_TOKEN}
    JWT_SECRET: ${env:JWT_SECRET}

plugins:
  - serverless-esbuild

functions:
  api:
    handler: handler.handler
    events:
      - http:
          path: /{proxy+}
          method: ANY
      - http:
          path: /
          method: ANY
Step 4: Deploy
bash
serverless deploy --stage prod

步骤1:安装依赖
bash
npm install -D serverless serverless-esbuild
步骤2:创建
handler.ts
typescript
import { createHandler } from "bknd/adapter/aws";

export const handler = createHandler({
  connection: {
    url: process.env.DB_URL!,
    authToken: process.env.DB_TOKEN,
  },
  isProduction: true,
  auth: {
    jwt: { secret: process.env.JWT_SECRET! },
  },
});
步骤3:创建
serverless.yml
yaml
service: bknd-api

provider:
  name: aws
  runtime: nodejs20.x
  region: us-east-1
  environment:
    DB_URL: ${env:DB_URL}
    DB_TOKEN: ${env:DB_TOKEN}
    JWT_SECRET: ${env:JWT_SECRET}

plugins:
  - serverless-esbuild

functions:
  api:
    handler: handler.handler
    events:
      - http:
          path: /{proxy+}
          method: ANY
      - http:
          path: /
          method: ANY
步骤4:部署
bash
serverless deploy --stage prod

Pre-Deployment Checklist

部署前检查清单

bash
undefined
bash
undefined

1. Generate types

1. 生成类型定义

npx bknd types
npx bknd types

2. Test locally with production-like config

2. 使用类生产配置在本地测试

DB_URL="your-prod-db" JWT_SECRET="your-secret" npx bknd run
DB_URL="your-prod-db" JWT_SECRET="your-secret" npx bknd run

3. Verify schema sync

3. 验证Schema同步

Schema auto-syncs on first request in production

生产环境中首次请求时会自动同步Schema

undefined
undefined

Environment Variables (All Platforms)

全平台通用环境变量

VariableRequiredDescription
DB_URL
YesDatabase connection URL
DB_TOKEN
DependsAuth token (Turso/LibSQL)
JWT_SECRET
YesMin 32 chars for security
PORT
NoServer port (default: 3000)
变量名是否必填说明
DB_URL
数据库连接URL
DB_TOKEN
可选认证令牌(Turso/LibSQL需提供)
JWT_SECRET
长度至少32字符,用于安全验证
PORT
服务器端口(默认:3000)

Common Pitfalls

常见问题排查

"Module not found" for Native SQLite

「找不到Native SQLite模块」

Problem:
better-sqlite3
not available in serverless
Fix: Use LibSQL/Turso instead of file-based SQLite:
typescript
connection: {
  url: "libsql://your-db.turso.io",
  authToken: process.env.DB_TOKEN,
}
问题:
better-sqlite3
在无服务器环境中不可用
解决方案: 使用LibSQL/Turso替代文件型SQLite:
typescript
connection: {
  url: "libsql://your-db.turso.io",
  authToken: process.env.DB_TOKEN,
}

"JWT_SECRET required" Error

「JWT_SECRET必填」错误

Problem: Auth fails in production
Fix: Set JWT_SECRET environment variable:
bash
undefined
问题: 生产环境中认证失败
解决方案: 设置JWT_SECRET环境变量:
bash
undefined

Cloudflare

Cloudflare

wrangler secret put JWT_SECRET
wrangler secret put JWT_SECRET

Vercel

Vercel

vercel env add JWT_SECRET
vercel env add JWT_SECRET

Docker

Docker

docker run -e JWT_SECRET="your-secret" ...
undefined
docker run -e JWT_SECRET="your-secret" ...
undefined

Cold Start Timeouts (Lambda)

Lambda冷启动超时

Problem: First request times out
Fix:
  • Use lighter database (Turso over RDS)
  • Reduce bundle size
  • Enable provisioned concurrency for critical functions
问题: 首次请求超时
解决方案:
  • 使用轻量数据库(如Turso替代RDS)
  • 减小包体积
  • 为核心函数启用预置并发

D1 Binding Not Found

D1绑定未找到

Problem:
env.DB is undefined
Fix: Check wrangler.toml D1 binding:
toml
[[d1_databases]]
binding = "DB"  # Must match env.DB in code
database_name = "my-database"
database_id = "actual-id-from-wrangler-d1-create"
问题:
env.DB is undefined
解决方案: 检查wrangler.toml中的D1绑定配置:
toml
[[d1_databases]]
binding = "DB"  # 必须与代码中的env.DB一致
database_name = "my-database"
database_id = "actual-id-from-wrangler-d1-create"

Media Uploads Fail in Serverless

无服务器环境中媒体上传失败

Problem: Local storage doesn't work in serverless
Fix: Use cloud storage adapter:
typescript
config: {
  media: {
    adapter: {
      type: "s3",  // or "r2", "cloudinary"
      config: { /* credentials */ },
    },
  },
}
问题: 本地存储在无服务器环境中无法工作
解决方案: 使用云存储适配器:
typescript
config: {
  media: {
    adapter: {
      type: "s3",  // 或 "r2", "cloudinary"
      config: { /* 凭据信息 */ },
    },
  },
}

CORS Errors

CORS错误

Problem: Frontend can't access API
Fix: Configure CORS in your adapter:
typescript
// Most adapters handle this automatically
// For custom needs, check platform docs
问题: 前端无法访问API
解决方案: 在适配器中配置CORS:
typescript
// 大多数适配器会自动处理此问题
// 如需自定义,请参考对应平台文档

Deployment Commands Reference

部署命令参考

bash
undefined
bash
undefined

Cloudflare Workers

Cloudflare Workers

wrangler deploy wrangler tail # View logs
wrangler deploy wrangler tail # 查看日志

Vercel

Vercel

vercel deploy --prod vercel logs
vercel deploy --prod vercel logs

Docker

Docker

docker compose up -d docker compose logs -f
docker compose up -d docker compose logs -f

AWS Lambda

AWS Lambda

serverless deploy --stage prod serverless logs -f api
undefined
serverless deploy --stage prod serverless logs -f api
undefined

DOs and DON'Ts

注意事项

DO:
  • Set
    isProduction: true
    in production config
  • Use cloud storage (S3/R2/Cloudinary) for media
  • Set strong JWT_SECRET (min 32 chars)
  • Enable Guard for authorization
  • Test with production database before deploying
  • Use environment variables for all secrets
DON'T:
  • Use file-based SQLite in serverless
  • Hardcode secrets in code
  • Deploy without testing schema sync
  • Use local storage adapter in production
  • Skip JWT_SECRET configuration
  • Commit
    .env
    files with real secrets
建议:
  • 在生产配置中设置
    isProduction: true
  • 使用云存储(S3/R2/Cloudinary)存储媒体文件
  • 设置强JWT_SECRET(至少32字符)
  • 启用Guard进行授权管理
  • 部署前使用生产数据库测试
  • 所有密钥均通过环境变量配置
禁止:
  • 在无服务器环境中使用文件型SQLite
  • 在代码中硬编码密钥
  • 未测试Schema同步就部署
  • 在生产环境中使用本地存储适配器
  • 跳过JWT_SECRET配置
  • 提交包含真实密钥的
    .env
    文件

Related Skills

相关技能

  • bknd-database-provision - Set up production database
  • bknd-production-config - Production security settings
  • bknd-storage-config - Configure media storage
  • bknd-env-config - Environment variable setup
  • bknd-local-setup - Local development (pre-deploy testing)
  • bknd-database-provision - 配置生产环境数据库
  • bknd-production-config - 生产环境安全设置
  • bknd-storage-config - 媒体存储配置
  • bknd-env-config - 环境变量配置
  • bknd-local-setup - 本地开发环境搭建(部署前测试用)