# Dify starts with four Docker commands, and the API underneath is Flask

> This is an LLM application platform you can take as a hosted service, self-host with Docker Compose, or license through an enterprise agreement. The quick start is four commands and a browser wizard, but the repository is a mixed TypeScript and Python tree with a lint stack of four tools and a Makefile that defaults every image to the latest tag.

**langgenius/dify** — Dify is an open-source LLM app platform combining agentic workflows, RAG pipelines and model management, deployable on cloud, VPC, or self-hosted infrastructure.

- Repository: https://github.com/langgenius/dify
- Website: https://dify.ai
- Stars: 157,512 · Forks: 24,826
- Language: TypeScript
- License: not declared
- Published: 2026-08-08 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/langgenius-dify

## The whole install is four commands, and initialization happens in a browser

The stated minimum is a two core CPU and 4 GiB of RAM, and the tooling requirement is Docker with Docker Compose v2.24.0 or later. The quick start is the entire procedure.

```bash
cd dify
cd docker
cp .env.example .env
docker compose up -d
```

The compose file is docker/docker-compose.yaml, and the copy step is what creates the environment file the stack reads. Once the containers are up, the dashboard is at http://localhost/install and the first thing you do there is run the initialization process, which is a browser wizard rather than an edited config file.

Two things follow for anyone sizing this. The 4 GiB figure is a floor for getting the stack running and building a workflow, not a production sizing guide, and the README does not give a larger one. And the initialization step is a web session, which means the first run is not reproducible from a script: an unattended deployment has to walk that URL before anything else will work.

## The recorded primary language is TypeScript, and the API is a Flask application

The repository is recorded as a TypeScript project, and the top level carries pnpm-lock.yaml, pnpm-workspace.yaml, tsconfig.json and a TypeScript-flavoured lint configuration. Look at the Makefile's prepare-api target and the picture changes.

```make
prepare-api:
	@cp -n api/.env.example api/.env 2>/dev/null || echo "API .env already exists"
	@cd api && uv sync --dev
	@cd api && uv run flask db upgrade
```

uv resolves the Python dependencies, and flask is the application framework, and the last line applies a database migration. So the backend under api/ is Python with its own dependency manager and its own schema history, while web/ and packages/ are the TypeScript side.

The practical consequence is that a team arriving for a TypeScript project acquires a second runtime, a second lockfile, and a migration step that the four quick start commands do not perform at all. The quick start path uses the compose stack, where migrations are somebody else's problem. It is only when you work from source that you meet uv and flask db upgrade.

## Every devDependency resolves through the pnpm catalog, so package.json has no versions

Read the dependency block at the root of package.json and there are no version numbers in it. The entries are specifiers, including `"@typescript-eslint/parser": "catalog:"` and `"eslint": "catalog:"`, and the same form repeats for the plugins, the parsers and the test tooling.

That is the pnpm catalog protocol. The versions live somewhere other than package.json, which for a pnpm workspace means pnpm-workspace.yaml, and package.json only says which catalog entry each dependency should take.

The consequence bites whoever has to change a version. Upgrading eslint in package.json does nothing, because there is no version there to upgrade. You have to find the catalog definition, change it, and then reconcile the lockfile. A reviewer looking at a dependency bump diff in package.json sees a catalog reference and has to go looking for the number, and an audit that reads package.json directly finds no versions to reason about. The benefit is that one edit moves every workspace that shares the catalog entry, which is a real gain in a tree this wide.

## Four lint tools, a knip guard script, and a file named oxlint-suppressions.json

The root package is not an application. It is named dify, marked private, set to type module, and its scripts are all linting and workspace tasks: check, check:fix, prepare, four oxlint variants, three eslint variants, two tailwind variants, and three knip variants.

The tailwind ones are worth noting for what they enforce. Both set TAILWIND_CANONICAL_CLASSES=true, so the lint pass is checking that class names match a canonical set rather than accepting near-miss spellings.

The knip entry is the most interesting. knip:production runs against the web workspace with --production and --include files, and then a separate script, knip:production-unused-check, runs check-web-production-unused-after-knip-fix.mjs. That is a guard asserting the knip fix was actually applied, which is a different kind of check from running knip.

Then there is the filename. oxlint-suppressions.json sitting at the top level is a record of rules that were turned off. And lint:eslint:quiet is wired next to it, so a second linter runs over the same tree. For a contributor, the practical cost is four commands to learn and a suppressions file whose contents you did not write and are expected to respect.

## VERSION=latest, so two developers on different days get different stacks

The Makefile opens with its variables, and the fourth one decides what you run.

```make
DOCKER_REGISTRY=langgenius
WEB_IMAGE=$(DOCKER_REGISTRY)/dify-web
API_IMAGE=$(DOCKER_REGISTRY)/dify-api
SANDBOX_RUNTIME_IMAGE=$(DOCKER_REGISTRY)/dify-agent-local-sandbox
VERSION=latest
```

Three images from one registry, all tagged latest by default. The prepare-docker target copies docker/envs/middleware.env.example to docker/middleware.env only if the latter is missing, then brings up docker-compose.middleware.yaml with a project name of dify-middlewares-dev. The middleware environment is therefore sticky on your machine once created, and editing the example does nothing until you delete the copy.

The consequence is a local stack that is not reproducible. Nothing in the quick start pins an image digest, so a bug that reproduces on your machine and not on a colleague's is at least as likely to be a different set of images as a different commit. It is also a second version namespace: releases are numbered, 1.17.1 on 2026-09-10 preceded by 1.17.0 and 1.16.1, and the last push was on 2026-09-29, but the tag on the image you pull is latest. The release number and the image tag are not the same thing.

## The agent sandbox is a third image, and the agent is described as building itself

Three source trees carry the runtime: web/, api/ and dify-agent/, alongside dify-agent-runtime/. The Makefile names the image that backs the last one, dify-agent-local-sandbox, as a variable in its own right rather than reusing the web or API image.

That separation is deliberate, and it matches what the README says agents do. Agents are described as having a sandbox of their own, running commands, installing software and handling files to get open-ended tasks done. That is a container whose image is a Makefile variable, separate from the one serving your chat app.

The same paragraph says to describe the agent you want and it builds itself, then give it skills, connect tools from the Dify Marketplace, MCP servers or your own APIs, and use it as a chat app or a step in a workflow. So the thing that executes inside the sandbox is partly generated, and the tools it can reach are ones you connected by giving it a server address. The boundary that keeps this contained is the sandbox image, which is also the piece whose tag defaults to latest. Pin that image before you let an agent install software.

## SSO, RBAC and support SLAs are an enterprise form, not the community edition

The way you use Dify is presented as three named options, and the split between them is a feature list rather than a tier list.

Dify Cloud is the hosted option, with plans and usage allowances on the pricing page and a support contact address. Self-hosting Dify Community Edition is the path the starter guide serves, the one the four quick start commands belong to. Dify Enterprise is for organizations requiring self-hosting, SSO, RBAC security and Enterprise support SLAs, and it is reached by filling in a form to speak to a solution representative.

Read the Enterprise line literally. Self-hosting is named on both sides, so the differentiator between running the Community Edition yourself and Enterprise is not the hosting, it is SSO, role-based access control and the support SLA. A team that needs to give twenty people separate permissions cannot get that from the free self-hosted path, because the README assigns it to a sales conversation. That is the first scoping question to answer, and it is cheaper to answer before the install than after.

## A LICENSE file at the root, an unresolved identifier, and no licence named in the README

There is a LICENSE file in the top-level listing of this repository. The licence identifier attached to the repository is unresolved, so automated tooling reports nothing rather than a name, and the README does not name a licence in any section of it.

Those three facts sit together without contradicting each other, and the practical effect is the same: a scanner, a procurement form or a legal review gets a blank where it expected a string, and the only place the terms are stated is a file someone has to open and read. This is not a claim about what the file says, which is not visible from the outside, and it is not a reason to avoid the project.

It is a reason to read it before you do anything else with it, because this is a platform whose entire purpose is to hold your documents, your prompts and your model credentials. Dify is also offered under three commercial shapes, Cloud, a self-hosted Community Edition and Enterprise through a sales conversation, and the terms that govern your deployment are the ones in that file, not the ones a licence detector guesses.

## Conclusion

Use the self-hosted Community Edition to evaluate Dify on your own data, since the install is four commands against a 4 GiB floor and needs nothing but Docker. Do not plan around SSO or role-based access on that edition, because the README places both under Dify Enterprise and a sales form, and check the LICENSE file at the repository root before you commit to it, since the licence identifier attached to the repository is unresolved and the README names no licence at all. Before putting anything in front of a team, pin the three images yourself instead of accepting the Makefile's default of latest, and read api/.env.example, because the API is a Flask application with its own dependency sync and its own schema migration step that the four quick start commands do not perform.

## FAQ

### What is langgenius dify?

Dify is an open-source LLM app development platform whose interface combines AI workflow building, a RAG pipeline, agent capabilities, model management and observability integrations including Opik, Langfuse and Arize Phoenix. You can use it as Dify Cloud, self-host the Community Edition, or talk to the project about Dify Enterprise for self-hosting with SSO, RBAC and support SLAs.

### What are the minimum system requirements to run Dify?

A CPU of at least 2 cores and RAM of at least 4 GiB, and Docker with Docker Compose v2.24.0 or later must be installed before you run the compose file. Those figures are the stated floor for getting the server started, and the README does not give a larger production sizing guide.

### How do I install Dify with Docker Compose?

Change into the repository, then into the docker directory, copy .env.example to .env, and bring the stack up with docker compose up -d. The compose file is docker/docker-compose.yaml, and once the containers are running you open http://localhost/install in a browser to run the initialization process.

### Does the self-hosted Dify Community Edition include SSO and RBAC?

Not according to how the README splits the offerings. Self-hosting with SSO, RBAC security and Enterprise support SLAs is listed under Dify Enterprise, which you reach by filling in a form to speak to a solution representative, while the self-hosted Community Edition is the path the starter guide and the Docker Compose quick start serve.

### Which languages is the Dify codebase written in?

The repository is recorded as a TypeScript project, and the web side uses pnpm workspaces with TypeScript linting. The API tree under api/ is Python: the Makefile syncs its dependencies with uv and applies database changes with uv run flask db upgrade, so a source-based setup involves a second runtime and its own migration step.

## Sources

- [Official documentation](https://dify.ai)
- [Official README](https://github.com/langgenius/dify#readme)
- [Project repository](https://github.com/langgenius/dify)
- [Release notes](https://github.com/langgenius/dify/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/langgenius-dify
