Add Zitadel to an existing app
Run setup in an app you already have, what it writes for each framework, and when it stops instead.
In an app you already have, setup detects the framework and patches the app instead of scaffolding a new one. You need what the Quickstart needs. Commit your work, then run these in the app's directory:
npx @zitadel/cli@latest doctor
npx @zitadel/cli@latest start
npx @zitadel/cli@latest setup --server localSetup asks the same questions and writes the same Zitadel files as for a new app (Scaffold auth). Then prove the browser flow as the Quickstart does.
What setup writes, by framework
- Next.js and Nuxt: setup detects the framework and patches the app. Before it creates anything, it stops with
E_CONFLICTrather than overwrite a file of yours that it would write, such as your ownproxy.tsorapp/login/page.tsx. Next.js runs one request boundary, so setup also stops on yours under the other name: on Next 16 it writesproxy.ts, and Next refuses to run beside amiddleware.ts. Move yours aside, rerun setup, and merge it into the file setup writes. Ifpackage.jsonnames Next.js by a tag such aslatest, setup can't tell the version and writesmiddleware.ts, so it stops on an existingproxy.ts: pin the version the app runs, such as^16.0.0, and rerun. - SvelteKit, SolidStart, Qwik Router, and TanStack Start: setup detects the framework and writes the server hook or middleware (
src/hooks.server.ts,src/middleware.ts,src/routes/plugin@nextgen.ts, orsrc/start.ts) plus the landing, login, register, and profile routes. - React, Vue, Angular, Solid, Svelte, and Qwik: setup writes the app's root component to a fixed path:
src/App.tsx(React, Solid),src/App.vue,src/App.svelte,src/app.tsx(Qwik), orsrc/app/app.ts(Angular). If your app has a file there, setup stops withE_CONFLICTon it, again before creating anything. It also reads the entry that mounts your root component, the scriptindex.htmlloads or Angular'ssrc/main.ts, and stops when that mounts one from another file, such assrc/App.jsxor Angular 17–19'ssrc/app/app.component.ts, because your app would never load setup's. Import the root from the path setup writes in that entry, rerun setup, and move what you need from yours into it. - Other apps, such as a Next.js Pages Router app, a React app without Vite, or an app on a framework older than setup supports (Next.js 15.2.3, Nuxt 4, SvelteKit 3 with Svelte 5, SolidStart 2, Qwik Router and Qwik 2.0.0-beta.45, TanStack Start 1, React 18, Vue 3.2, Angular 17, Solid 1.6, Svelte 5): setup doesn't support them yet and stops without changing anything. Don't pass
--forcethere: where setup detects no framework at all,--forcemakes it scaffold a new app over yours.
When setup stops
If you pass --framework, name the one your app uses: when setup detects another, it stops with E_CONFLICT instead of treating your app as a directory to scaffold into. The files setup writes under .zitadel/, such as the default schema and login flow, are checked before it creates the project too, so a conflict leaves nothing behind.
After an E_CONFLICT, the error's hint says what to change. For a file at a path setup writes, move it aside and rerun, or rerun with --force to let setup replace it and merge your version back from git. --force doesn't help with your root component or request boundary at another path, or with a connection under .zitadel/idps/, which setup never replaces.
Was this helpful?