Running Keycloak react admin-ui as dev mode
08:19 02 Nov 2025

I want to make some changes to the admin-ui of Keycloak and make it the way I want. But I can't run the project in development mode. Is there a way that I can run the admin-ui project in development mode so that I can see it immediately after making the changes. When I use pnpm run dev, I get a 404 error on localhost:5174.

In keycloak-26.4.2/bin I run backend as dev by this command: kc.bat start-dev. Then keycloak backend will run. Next in keycloak-main/js/apps/admin-ui I run pnpm run dev:

VITE v7.1.10  ready in 2182 ms
  ➜  Local:   http://localhost:5174/
  ➜  Network: http://192.168.61.12:5174/

But keycloak is not accessible on localhost:5174. The request:

Request URL http://localhost:5174/
Request Method GET
Status Code 404 Not Found Remote Address [::1]:5174
Referrer Policy strict-origin-when-cross-origin 

Keycloak v26.4.2 and Node v22.21.0

admin-ui/package.json:

{
  "name": "@keycloak/keycloak-admin-ui",
  "version": "999.0.0-SNAPSHOT",
  "type": "module",
  "main": "lib/keycloak-admin-ui.js",
  "types": "./lib/keycloak-admin-ui.d.ts",
  "exports": {
    ".": {
      "import": "./lib/keycloak-admin-ui.js",
      "types": "./lib/keycloak-admin-ui.d.ts"
    }
  },
  "files": [
    "lib"
  ],
  "publishConfig": {
    "access": "public"
  },
  "scripts": {
    "dev": "wireit",
    "build": "wireit",
    "build-lib": "wireit",
    "preview": "wireit",
    "lint": "wireit",
    "test": "wireit",
    "test:integration": "wireit"
  },
  "wireit": {
    "dev": {
      "command": "vite --host",
      "dependencies": [
        "../../libs/ui-shared:build",
        "../../libs/keycloak-admin-client:build"
      ]
    },
    "preview": {
      "command": "vite preview",
      "dependencies": [
        "../../libs/ui-shared:build",
        "../../libs/keycloak-admin-client:build"
      ]
    },
    "build": {
      "command": "vite build",
      "dependencies": [
        "../../libs/ui-shared:build",
        "../../libs/keycloak-admin-client:build"
      ],
      "files": [
        "public",
        "src",
        "tsconfig.json",
        "vite.config.ts"
      ],
      "output": [
        "target/classes/theme/keycloak.v2/admin/resources"
      ]
    },
    "build-lib": {
      "command": "cross-env LIB=true vite build",
      "dependencies": [
        "../../libs/ui-shared:build",
        "../../libs/keycloak-admin-client:build"
      ]
    },
    "lint": {
      "command": "eslint .",
      "dependencies": [
        "../../libs/ui-shared:build",
        "../../libs/keycloak-admin-client:build"
      ]
    },
    "test": {
      "command": "vitest",
      "dependencies": [
        "../../libs/ui-shared:build",
        "../../libs/keycloak-admin-client:build"
      ]
    },
    "test:integration": {
      "command": "playwright test",
      "dependencies": [
        "../../libs/keycloak-admin-client:build"
      ]
    }
  },
  "dependencies": {
    "@dagrejs/dagre": "^1.1.5",
    "@keycloak/keycloak-admin-client": "workspace:*",
    "@keycloak/keycloak-ui-shared": "workspace:*",
    "@patternfly/patternfly": "^5.4.2",
    "@patternfly/react-core": "^5.4.14",
    "@patternfly/react-icons": "^5.4.2",
    "@patternfly/react-styles": "^5.4.1",
    "@patternfly/react-table": "^5.4.16",
    "@uiw/react-textarea-code-editor": "^3.1.1",
    "admin-ui": "file:",
    "file-saver": "^2.0.5",
    "flat": "^6.0.1",
    "i18next": "^25.6.0",
    "i18next-fetch-backend": "^6.0.0",
    "jszip": "^3.10.1",
    "keycloak-js": "^26.2.0",
    "lodash-es": "^4.17.21",
    "p-debounce": "^5.0.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-hook-form": "^7.63.0",
    "react-i18next": "^16.0.1",
    "react-router-dom": "^6.30.1",
    "reactflow": "^11.11.4",
    "use-react-router-breadcrumbs": "^4.0.1"
  },
  "devDependencies": {
    "@axe-core/playwright": "^4.10.2",
    "@playwright/test": "^1.56.0",
    "@testing-library/dom": "^10.4.1",
    "@testing-library/jest-dom": "^6.9.1",
    "@testing-library/react": "^16.3.0",
    "@types/dagre": "^0.7.53",
    "@types/file-saver": "^2.0.7",
    "@types/lodash-es": "^4.17.12",
    "@types/react": "^18.3.18",
    "@types/react-dom": "^18.3.5",
    "@vitejs/plugin-react-swc": "^4.1.0",
    "cross-env": "^10.1.0",
    "jsdom": "^27.0.0",
    "lightningcss": "^1.30.2",
    "properties-file": "^3.6.1",
    "ts-node": "^10.9.2",
    "uuid": "^13.0.0",
    "vite": "^7.1.10",
    "vite-plugin-checker": "^0.11.0",
    "vite-plugin-dts": "^4.5.4",
    "vitest": "^3.2.4"
  },
  "author": {
    "name": "Red Hat, Inc.",
    "url": "https://www.keycloak.org/"
  },
  "license": "Apache-2.0",
  "repository": {
    "type": "git",
    "url": "https://github.com/keycloak/keycloak.git",
    "directory": "js/apps/admin-ui"
  },
  "homepage": "https://www.keycloak.org/"
}

admin-ui/vite-config.ts:

import react from "@vitejs/plugin-react-swc";
import { readFileSync } from "node:fs";
import path from "path";
import { getProperties } from "properties-file";
import { defineConfig, loadEnv } from "vite";
import { checker } from "vite-plugin-checker";
import dts from "vite-plugin-dts";
import { configDefaults } from "vitest/config";

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), "");
  const external = ["react", "react/jsx-runtime", "react-dom"];
  const plugins = [
    react(),
    checker({ typescript: true }),
    {
      name: "message-bundle-transformer",
      resolveId(source) {
        if (source === "message-bundle") {
          return source;
        }
        return null;
      },
      load(id) {
        if (id === "message-bundle") {
          let properties = {};
          if (process.env.NODE_ENV === "development") {
            properties = getProperties(
              readFileSync(
                "./maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties",
              ),
            );
          }
          return {
            code: `export default ${JSON.stringify(properties)};`,
          };
        }
        return null;
      },
    },
  ];
  const input = env.LIB ? undefined : "src/main.tsx";
  if (env.LIB) {
    external.push("react-router-dom");
    external.push("react-i18next");
    plugins.push(dts({ insertTypesEntry: true }));
  }

  const lib = env.LIB
    ? {
        outDir: "lib",
        lib: {
          entry: path.resolve(__dirname, "src/index.ts"),
          formats: ["es"],
        },
      }
    : {
        outDir: "target/classes/theme/keycloak.v2/admin/resources",
        external: ["src/index.ts"],
      };
  return {
    base: "",
    server: {
      origin: "http://localhost:5174",
      port: 5174,
    },
    build: {
      ...lib,
      sourcemap: true,
      target: "esnext",
      modulePreload: false,
      cssMinify: "lightningcss",
      manifest: true,
      rollupOptions: {
        input,
        external,
      },
    },
    plugins,
    test: {
      watch: false,
      environment: "jsdom",
      exclude: [...configDefaults.exclude, "./test/**"],
      server: {
        deps: {
          inline: [/@patternfly\/.*/],
        },
      },
    },
  };
});

What is the way I can run the react admin-ui on the dev mode? Thanks a lot.

javascript reactjs keycloak