说实话,把Dify在Windows 11上从零跑起来这件事,网上的教程大多数都停留在“用Docker Compose一把梭”的阶段。但真正到开发阶段——比如你要改后端代码、调试前端工作流、加自定义工具——纯容器化部署反而不方便,因为你得重新构建镜像才能让改动生效。我这次用的是源码方式跑Dify,配合Python 3.11和Node.js 18,中间踩了不少坑,尤其是前端依赖安装时报的那几个ESM相关错误,折腾了大半个晚上才定位到根因。这篇文章就是把这些过程完整记录下来,给想在Windows 11上本地开发Dify的人一个可以直接照着走的参考,而不是只给一句“请参考官方文档”。
1. 为什么选Python 3.11和Node.js 18这套环境组合
1.1 Dify对运行时版本的要求
先看官方仓库的说明,Dify 1.17.1版本对应的后端API是一个Python项目,前端Web是一个Next.js项目。两套代码的运行环境要求非常明确:后端建议Python 3.11,前端建议Node.js 18。
我在准备环境时也特意对比了一下版本依赖关系,Dify的api/requirements.txt里有很多依赖包在Python 3.12上会有兼容性问题,比如某些C扩展库还没有发布对应wheel包,源码编译在Windows上会非常痛苦。我试过在Python 3.12上直接跑pip install -r requirements.txt,结果有一个依存库在安装阶段就报错,提示需要Visual Studio的C++构建工具,后来换回3.11就完全正常。这个经验告诉我:在Windows上,不要试图用“最新版Python”去跑一个生产级开源项目,除非官方明确写了支持。
Node.js 18也同理。Dify前端的Next.js版本、依赖的Swagger客户端、各种Babel插件,在Node 20以后基本也能跑,但在Node 22上偶尔会出现一些不兼容告警。官方既然把Node 18写成要求,就一定有他们的道理——我在实际安装中切回Node 18后,之前遇到的若干ESM报错全都消失了。
1.2 源码运行与容器化运行的路线差异
这里先把部署路线讲清楚,因为后续所有操作都取决于你选哪条路。
| 对比项 | Docker Compose部署 | 源码运行 |
|---|---|---|
| 安装复杂度 | 低,一条命令拉起所有中间件 | 高,需要手动装Python、Node、PostgreSQL、Redis |
| 开发调试 | 困难,代码改动后需重新构建镜像 | 方便,热更新即时生效 |
| 资源占用 | 镜像体积大,多个容器常驻 | 相对轻量,只启动4个左右进程 |
| 学习价值 | 了解整体架构 | 能深入理解Dify的启动流程和依赖关系 |
| 适合场景 | 快速体验、部署到服务器 | 二次开发、源码学习、调试 |
如果你只是想体验Dify功能,那Docker Compose是最优解。但你想改前端页面、改后端API、接入内部系统,源码运行是唯一合理路径。这篇文章接下来的内容全部围绕源码运行展开,但我会在最后补充一个“容器化部署时的坑”,方便选择Docker路线的朋友参考。
2. Windows 11下手把手安装Python 3.11与Node.js 18
2.1 Python 3.11安装:版本选择、PATH勾选与验证
Python的安装本身并不复杂,但有几个细节决定了你后面能否少踩坑。
第一,不要从Windows Store安装Python。Store版本默认装到C:\Users\你的用户名\AppData\Local\Microsoft\WindowsApps下,权限和PATH行为都跟官方安装包不一样,后面用py -3.11命令时也容易混。我建议直接从python.org下载Windows installer (64-bit)。
第二,安装向导里一定要勾选“Add Python 3.11 to PATH”,这一步如果你漏了,后面所有python命令都会提示“不是内部或外部命令”。很多人以为勾不勾无所谓,反正可以用py启动器——但Dify后端的启动脚本、pip命令,很多地方是直接调用python的。
第三,安装时选择“Customize installation”,确保pip、tcl/tk、Python test suite这些组件都勾上。tcl/tk某些依赖库在后续用到时会需要,而pip是必须的。
安装完以后,在PowerShell或CMD里验证:
python --version输出应该是Python 3.11.x。如果输出的是Python 3.13之类,说明你系统里还有别的Python进PATH了,用where python查看到底命中了哪个路径。
我建议顺便配一下pip国内镜像源(如果网络环境访问PyPI较慢的话),在用户目录下新建pip.ini:
[global] index-url = https://pypi.tuna.tsinghua.edu.cn/simple trusted-host = pypi.tuna.tsinghua.edu.cn2.2 Node.js 18安装与npm源配置
Node.js 18的安装同样从官网下Windows LTS安装包。不过要注意,我强烈建议直接装nvm-windows来管理Node版本,而不是直接装Node.js 18的MSI包。原因很简单:Dify前端的依赖树非常复杂,假如你后续还要开发其他Node项目,一定会有版本冲突。用nvm-windows可以在不同Node版本之间一键切换,省去反复卸载重装的麻烦。
如果你确实不想装nvm,直接装Node 18.20.x LTS版也行,记得安装向导里勾选“Add to PATH”。
安装完成后同样验证:
node -v npm -v我本机的输出是v18.20.4和10.7.0,你要是版本号接近就没问题。
npm源配置也比较关键,直接在全局层面把registry换成国内镜像:
npm config set registry https://registry.npmmirror.com换完后跑一下npm config get registry确认是否生效。这一步能极大减少后续npm install时的等待时间和失败概率。
2.3 Windows 11特有的环境细节
Windows 11上做这套开发,有几个隐藏的坑值得单独说。
第一个是“路径长度限制”。Windows默认的MAX_PATH是260字符,而Dify前端的node_modules目录嵌套层级很深,文件路径很容易超过这个限制。安装Node.js后,在“组策略”里可以开启长路径支持,也可以用gpedit.msc去改,但更快的办法是:在PowerShell里用管理员权限执行:
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force改完后重启一次。如果我不做这步,后面npm install大概率会在某个子模块上报ENAMETOOLONG或文件复制失败。
第二个是Windows Defender实时扫描。node_modules目录动辄几万个小文件,Defender扫描会让安装速度变得非常慢。我自己实践后建议:把Dify源码目录加入Defender的排除列表,或者至少把node_modules目录排除掉。这不是关闭安全软件,只是针对特定目录做性能优化。
第三个是PowerShell执行策略。如果你要直接执行某些.ps1脚本,需要先允许本机脚本运行。以管理员身份打开PowerShell执行:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser不然有些npm包在安装时会调用构建脚本(比如node-gyp),可能因为执行策略被拦下来。
3. Dify后端环境初始化:源码、依赖、配置文件
3.1 拉取源码与准备目录结构
选择你的工作目录,比如D:\dev,然后把Dify源码clone到本地:
cd D:\dev git clone https://github.com/langgenius/dify.git cd dify git checkout 1.17.1为什么建议直接切到1.17.1这个tag?因为我写这篇文章时的最新发布版是1.17.1,而且从热点讨论看,这个版本在Windows下踩坑点最少,新人用稳定版而不是main分支是最稳妥的。切到tag之后,源码目录下你应该能看到:
api/:后端的Flask项目web/:前端的Next.js项目docker/:容器部署用的compose文件与.env示例plugin/:插件机制相关代码
在Windows上我不会去克隆plugin仓库的子模块,这会在后面单独说明。
3.2 .env配置里最容易踩的坑
后端启动前有几件事必须干,第一件就是配置环境变量。Dify官网文档里写的是“copy .env.example to .env”,但Windows下实际操作时,你得先看api/.env.example里每个变量是干嘛的,因为源码模式跟docker模式默认配置不太一样。
我列几个我实际踩过、后来仔细看文档才明白的关键变量:
| 变量名 | 我的取值 | 说明 |
|---|---|---|
SECRET_KEY | 随机生成一串64位字符串 | 不设置的话后端会启动失败 |
DB_HOST | localhost | 数据库地址,源码运行时不走容器内网 |
DB_PORT | 5432 | PostgreSQL默认端口 |
DB_USERNAME | postgres | 数据库用户名 |
DB_PASSWORD | 你自己的密码 | 需保证和PostgreSQL一致 |
REDIS_HOST | localhost | Redis地址 |
REDIS_PORT | 6379 | Redis默认端口 |
MODE | local | 定位为本地开发模式 |
生成SECRET_KEY的命令:
python -c "import secrets; print(secrets.token_hex(32))"复制输出值填到.env里。
这里的核心逻辑是:源码运行的后端,默认不自己去启动数据库和Redis,它需要你在外部启动这些依赖服务并告诉它连接地址。我先说结论:PostgreSQL和Redis用Docker容器来启动,后端用Python源码跑,这是最省事的组合。因为Windows本地直接装PostgreSQL会比较麻烦(服务注册、密码策略、PATH),而Docker Desktop在Windows 11上的体验已经很成熟。
3.3 启动PostgreSQL与Redis
在Dify源码目录下,官方其实提供了一个docker/docker-compose.yaml,里面有postgres、redis、sandbox、weaviate等服务的定义。我采用的方式是先从docker目录拷贝一份compose文件,然后只挑出PostgreSQL和Redis跑起来。
新建一个dev-middleware/docker-compose.yaml,写入:
version: '3.8' services: postgres: image: postgres:15-alpine container_name: dify-postgres environment: POSTGRES_PASSWORD: dify_password POSTGRES_DB: dify POSTGRES_USER: postgres ports: - "5432:5432" volumes: - pgdata:/var/lib/postgresql/data redis: image: redis:6.2-alpine container_name: dify-redis ports: - "6379:6379" volumes: pgdata:然后:
cd dev-middleware docker compose up -d等容器启动后,验证连接:
docker ps看到dify-postgres和dify-redis都是Up状态就说明中间件OK了。此时用本机的psql或者其他数据库工具(比如DBeaver)连一下localhost:5432,能连上就说明网络、端口、账号密码都没问题。
这一步的目的是把外置依赖从应用代码里剥离开。这样后续排查问题时,你可以快速判断是数据库的问题还是Dify后端的问题,不用一锅炖。
4. 前端依赖安装:node:util报错的完整排查链路
4.1 从报错信息到根因定位
前端环境初始化本来是三步:cd web、npm install、npm run dev。但我在实际运行中,npm install完成后执行npm run dev,直接遇到了一段让我卡了很久的报错:
node:internal/modules/esm/resolve:XXX Error [ERR_NO_EXPORT]: The requested module 'node:util' does not provide an export named 'xxx'报错指向node:util,意思是在node:util这个内置模块里找不到某个命名导出。这个报错很容易让人误判成“Node版本不够高”,因为util.parseArgs、util.types这些API都是后来才加进Node的。我当时第一反应是切换到Node 20,结果仍然报错,只是报错位置换了。
后来我仔细查看了完整的报错堆栈,发现触发报错的文件是web/node_modules/xxx/xxx.js,而不是Dify自己的源码。也就是说:某些第三方依赖在安装时选错了版本,导致它在运行时调用了当前Node环境不提供的API。
排查链路是这样的:
- 在报错堆栈中找到第一个非
node_modules的引用,确认是哪个包在调用node:util。 - 打开那个包的
package.json,看它的engines字段要求和它依赖的Node版本范围。 - 检查Dify官方文档里对包管理器的要求——Dify前端推荐用pnpm或者yarn,而不是npm。
第四步就是根因所在。我最初直接用npm安装依赖,但Dify前端的web/package.json里同时存在package-lock.json、yarn.lock等不同时代的锁文件线索。npm在解析依赖时,可能会把某些ESM-only的包解析到不兼容的版本。切换到yarn并删除旧的node_modules后重新安装,问题彻底消失。
4.2 依赖安装的版本管控方案
为了避免再次陷入“依赖版本地狱”,我在Dify前端目录下用了这样一组操作:
cd web # 彻底清理旧依赖与缓存 rm -rf node_modules npm cache clean --force # 切换包管理器 corepack enable yarn install使用yarn而不是npm有两个好处:其一是yarn在解析依赖时以yarn.lock为准,而Dify官方是推送过yarn.lock的,所以锁文件存在且完整;其二,yarn在Windows上对符号链接、路径长度、并行下载的处理更加稳定。
安装完成后,我建议执行一次yarn why <包名>来看某个关键依赖的解析路径,比如:
yarn why some-package它能清晰地列出顶层依赖和嵌套依赖关系,比npm的ls命令直观很多。
4.3 pip install与npm install的常见网络问题
说完了版本问题,再补充一下网络问题。如果你在安装后端依赖或前端依赖时频繁失败,别急着怀疑依赖冲突,先看一下是不是网络传输导致的包不完整。
后端依赖安装:
cd api pip install -r requirements.txt如果某个包一直下载到一半报错,大概率是网络不稳。解决办法是用专线pip源或者设置超时时间:
pip install -r requirements.txt --timeout 120前端依赖安装也有同样的网络问题。yarn安装时如果卡住,可以试试更激进的镜像配置:
yarn config set registry https://registry.npmmirror.com实操中还发现一个细节:yarn的缓存目录在C:\Users\用户名\AppData\Local\Yarn\Cache,如果你之前有过一次失败的下载,yarn并不会自动清除损坏的缓存文件。所以反复失败时,可以yarn cache clean后再装。
5. 启动完整Dify服务与开发环境验证
5.1 后端服务启动与初始化
后端依赖装好后,首先要执行数据库迁移:
cd api flask db upgrade这个命令会读取.env里的数据库连接信息,然后到PostgreSQL里自动创建Dify所需的表结构。如果这个步骤报错,九成是数据库连接参数错了,仔细检查.env里的DB_*四项。
迁移完成后,启动后端开发服务器:
flask run --host=0.0.0.0 --port=5001注意Dify后端的默认端口是5001,不是Flask默认的5000。启动日志里如果出现Running on http://0.0.0.0:5001,说明后端起来了。此时可以快速验证API是否正常:
curl http://localhost:5001/health正常会返回一个JSON,里面包含status字段。
5.2 前端Dev Server与账号创建
后端跑起来后,新开一个终端启动前端:
cd web yarn dev前端默认端口是3000。等编译完成,浏览器访问http://localhost:3000,Dify的引导页面就出来了。
首次访问会让你设置管理员账号,也就是Dify平台的“管理员邮箱+密码”。这里我建议用真实的常用邮箱,因为后续一些操作会用到这个账号的通知能力,虽然本地开发不一定要收邮件,但填一个你能记得住的邮箱最省事。
设置完成以后进入主界面,你会看到“创建空白应用”“从模板创建”“导入DSL文件”这几个选项。到这一步,Dify开发环境就算真正跑通了。
5.3 开发环境自检清单
环境跑通后,我建议按下面的清单过一遍,确认每个核心环节都可用:
- 工作流编辑器是否能正常打开:点进一个应用,看左侧的节点面板是否加载完整。
- 模型供应商是否配置:在“设置-模型供应商”里添加至少一个模型API Key(比如OpenAI兼容接口),然后在一个Prompt节点中选择该模型。
- 知识库上传是否成功:新建一个知识库,上传一个txt或markdown文件,等待分段与索引完成。如果这一步卡住,检查后端日志里的Weaviate或Qdrant连接状态。
- 调试对话是否能正常返回:在应用预览框里发一句话,看能否收到模型回复。
- 前后端热更新是否生效:改一行前端代码,浏览器页面能自动刷新;改一行后端代码,flask开发服务器会自动reload。
我这里再补充一个常见问题:如果你登录前端报跨域错误,检查一下.env里的CONSOLE_API_URL和APP_API_URL是否配置正确。
从我的经验来看,前面每一步都做对的话,这个清单基本上一次就能全过。但哪怕只有一项不通过,也建议不要跳过,因为Dify是一个前后端深度耦合的平台,某个环节没就绪,后面做插件开发或自定义工具时会有一堆莫名其妙的连锁问题。
最后再分享一个调试技巧:后端日志直接在终端里看,前端调试按F12看浏览器控制台。如果你发现后端API报500,但日志里没有具体堆栈,可以在api目录下设置环境变量FLASK_DEBUG=1再重启flask run,这样每次请求都会打出完整调用的堆栈信息,定位问题会快很多。
这套环境我已经连续用了差不多三周,中间跑过知识库接入、工作流编排、自定义工具调试,还没有遇到需要重启容器的场景。唯一一次较麻烦的是改了一版数据库迁移脚本,需要重置本地数据库重新初始化,其他时候Windows 11上这套组合的稳定性完全够用。如果你后续要研究Dify源码的插件机制,或者想往Dify里写自己的Node.js工具类,这套环境也会是很好的起点。