Skip to main content
Each release lists what changed, what to watch out for when upgrading, and every merged pull request. The same notes are published on GitHub. Self-hosting? Follow the upgrade steps for every upgrade.
19 October 2026

Overview

Formbricks 6.1 adds survey visibility, so organizations can restrict who sees each survey and its responses, and brings dark mode and Custom CSS to surveys. It also adds Qualtrics survey import from .qsf files, Embedded Data V2 with a shared field library, the v3 Responses API with matching MCP tools, and new chart types and filters.Self-hosters: follow the upgrade steps, and see the migration guide for details on each change. The tested upgrade pair for this release is 6.0.2 → 6.1.0. Kubernetes installs can opt into the online upgrade mode instead of a maintenance window; it is still under validation, so the maintenance path remains the default.Formbricks 6.1 receives bug fixes and security fixes until 19 January 2027.

⚠️ Breaking changes

6.1 is a minor release. It has no major breaking changes, only the smaller ones below, each of which affects a specific setup. As with every upgrade, follow the upgrade steps, which include a short maintenance window.Self-hosting
  • Encrypted single-use links stop working. Links created before 6.1 with URL encryption on (the default) are rejected after the upgrade. Re-create and re-send them. If you need more time, set SINGLE_USE_LEGACY_UNSIGNED_UNTIL to a date in YYYY-MM-DD format, for example 2026-11-15: old links keep working until 00:00 UTC on that day. Use it only on an instance that serves a single organization, because it re-opens the issue this release fixes. Unencrypted links and custom single-use IDs are not affected (#9131)
  • Helm: the web container is locked down. It now runs with a read-only root filesystem, as non-root user 1001, with all Linux capabilities dropped. This only affects custom images or sidecars that write inside the container: mount a writable path with deployment.extraVolumes and deployment.extraVolumeMounts, or set deployment.containerSecurityContext.readOnlyRootFilesystem: false. If you set deployment.securityContext.runAsUser, move it to deployment.containerSecurityContext.runAsUser, which now takes precedence (#9450)
  • Helm: AuthZed hooks run as user 1001. If your custom image needs another user, set authzed.initialization.securityContext.runAsUser (#9516)
  • Helm: taxonomy timeout overrides are validated. With taxonomy.enabled=true, rendering fails unless taxonomy.terminationGracePeriodSeconds is at least taxonomy.runDeadlineSeconds + 30, and taxonomy.hubStaleRunTimeoutSeconds is greater than taxonomy.runDeadlineSeconds. The defaults (900, 930 and 1800 seconds) pass (#9451)
API
  • Ending-card URLs need a real host. buttonLink and url on ending cards (v1, v2 and v3 survey create and update) must use a hostname with a dot (intranet.example.com), localhost or an IP address. A host like http://intranet now returns 400. Existing surveys keep loading; the rule applies when they are next saved (#9399)
  • Hidden fields can’t share a name with a question. Adding one on POST or PUT /api/v1/management/surveys returns 400. Existing surveys keep saving (#9467)
  • New survey limit per workspace. SURVEY_WORKSPACE_LIMIT (a number, default 10000, archived surveys included) caps the surveys in one workspace. Creating or copying a survey past it returns 422 workspace_survey_limit_reached on v1 and v3. Raise it before upgrading if a workspace is close (#9412)

🚀 Features

  • feat(webhooks): fan out webhook delivery into per-webhook background jobs by @xernobyl in #9123
  • feat(api-v3): OpenAPI contract for the v3 responses API by @xernobyl in #9167
  • feat(api-v3): shared response service, and both delete endpoints on top of it by @xernobyl in #9183
  • feat(api): edit and reorder survey blocks without resending the whole array by @xernobyl in #9186
  • feat(api-v3): keyset cursor helper, its Response indexes, and Sentry on v3 5xx by @xernobyl in #9222
  • feat(api-v3): response serializer and the three read endpoints by @xernobyl in #9237
  • feat(charts): add nested filter groups to chart filters [ENG-3149] by @Dhruwang in #9241
  • feat(surveys): report the survey card’s rect to native hosts by @pandeymangg in #9242
  • feat(api-v3): response writes — create and patch by @xernobyl in #9252
  • feat: add explicit AuthZed maintenance preparation by @BhagyaAmarasinghe in #9265
  • feat(mcp): add responses:read and responses:write scopes by @xernobyl in #9274
  • feat(mcp): name the survey element types on the tool surface by @xernobyl in #9320
  • feat(mcp): expose responses through the MCP server by @xernobyl in #9326
  • feat(i18n): support the full European language/locale matrix in surveys by @Dhruwang in #9332
  • feat(surveys): keep New Survey available while the list loads [ENG-2579] by @Dhruwang in #9344
  • feat: offer the Lite license at 2FA and the workspace limit instead of branding removal by @harshsbhat in #9347
  • feat(helm): support external embedding runtimes by @BhagyaAmarasinghe in #9363
  • feat(settings): organization usage page for self-hosted owners and managers by @Dhruwang in #9393
  • feat(api): record read-path metrics for the v3 responses API by @mattinannt in #9401
  • feat(surveys): allow mailto: links in survey text and ending buttons [ENG-3392] by @itsjavi in #9403
  • feat(authorization): survey visibility and its operational model [ENG-3282] by @Dhruwang in #9412
  • feat(charts): matrix chart — statements × scale points grid (ENG-3312) by @Dhruwang in #9415
  • feat(surveys): support an “Other” option in ranking questions by @Dhruwang in #9429
  • feat(ai): OAuth2 client-credentials auth for the openai-compatible provider [ENG-3226] by @Dhruwang in #9438
  • feat: show feedback record taxonomy in API and drawer by @BhagyaAmarasinghe in #9446
  • feat(charts): NPS & CSAT band dimension, fixed score axes, metric presets and response base [ENG-3331] by @Dhruwang in #9448
  • feat(helm): give the taxonomy pod its own ServiceAccount for workload identity by @BhagyaAmarasinghe in #9453
  • feat(embedded-data): Embedded Data V2 — field library, one Embedded Data card, typed fields by @pandeymangg in #9467
  • feat(mcp): offer responses:read / responses:write to OAuth MCP clients by @xernobyl in #9479
  • feat: add custom overlay color and opacity for app surveys by @pandeymangg in #9485
  • feat(email): tag SES messages by type and environment by @BhagyaAmarasinghe in #9502
  • feat(surveys): open multi-language surveys in the browser language, on one shared matcher by @Dhruwang in #9508
  • feat(auth): tell SSO users how to sign in and make forgot-password enumeration-safe [ENG-3262][ENG-3639][ENG-3640] by @xernobyl in #9511
  • feat(feedback-records): expose updated_since/updated_until for incremental extraction [ENG-3420] by @xernobyl in #9515
  • feat(i18n): ship Belgian Dutch and Swiss Italian survey bundles by @Dhruwang in #9539
  • feat: dark mode and Custom CSS for surveys by @itsjavi in #9549
  • feat: support taxonomy thinking levels and verify provider compatibility by @BhagyaAmarasinghe in #9561
  • feat(surveys): let creators set alt text for survey images by @Dhruwang in #9574
  • feat(actions): explain CSS selector syntax in the no-code click action by @jobenjada in #9575
  • feat(nav): remove Beta badge from the Analyze section by @jobenjada in #9583
  • feat(surveys): import Qualtrics surveys from .qsf files by @pandeymangg in #9595
  • feat: add guarded online 6.1 upgrades by @BhagyaAmarasinghe in #9609

🐛 Fixes

  • fix(surveys): bind encrypted single-use links to their survey by @xernobyl in #9131
  • fix(survey-editor): name the field behind a blocked publish [ENG-2833] by @Dhruwang in #9138
  • fix(sso): stop SSO recovery retries growing the URL into a 414 by @xernobyl in #9144
  • fix(surveys): settle navigation from an off-block blockId instead of throwing [ENG-2818] by @Dhruwang in #9149
  • fix: prompt to reload when a tab outlives its deployment [ENG-2330] by @Dhruwang in #9154
  • fix: respect PostgreSQL Helm overrides by @BhagyaAmarasinghe in #9221
  • fix(organization): mirror the server’s owner count in the members table [ENG-2616] by @pandeymangg in #9226
  • fix(unify): translate the strings frozen in English on Unify surfaces [ENG-2605] by @pandeymangg in #9227
  • fix(integrations): stop the disabled integration action from navigating [ENG-2608] by @pandeymangg in #9228
  • fix(i18n): correct mistranslated Dutch back/save buttons by @jobenjada in #9229
  • fix: terminate AuthZed health CLI after failures by @BhagyaAmarasinghe in #9232
  • fix(i18n): update Hungarian translations by @Dhruwang in #9234
  • fix(charts): resolve option labels from every mapped question [ENG-3140] by @Dhruwang in #9235
  • fix(charts): drop grouped rows no selected measure answers [ENG-3150] by @Dhruwang in #9239
  • fix(charts): keep one category label treatment on flipped bar charts [ENG-3148] by @Dhruwang in #9240
  • fix(ui): cap combobox option list inside its popover [ENG-3158] by @Dhruwang in #9243
  • fix(ui): match combobox search against the option label by @Dhruwang in #9245
  • fix(survey-link): stop a mounted gate fighting the language picker [ENG-3160] by @Dhruwang in #9246
  • fix(analysis): partition NPS and CSAT buckets exhaustively [ENG-3147] by @Dhruwang in #9248
  • fix(survey-editor): stop a disabled unit select covering the rule delete button [ENG-3175] by @Dhruwang in #9250
  • fix(responses): bound the “Other” response filter instead of permuting every subset by @xernobyl in #9253
  • fix(logger): resolve process handle through globalThis in Edge bundles [ENG-2602] by @itsjavi in #9267
  • fix(contacts): restore the clear control on date pickers [ENG-3084] by @itsjavi in #9289
  • fix(helm): support Gateway API v1.5 clusters by @BhagyaAmarasinghe in #9291
  • fix(sso): label provisioning rejections in the callback-outcome log by @xernobyl in #9294
  • fix(turbo): restore the copied SDK bundles from cache and hash the shared vite plugins by @xernobyl in #9297
  • fix(auth): restrict OAuth dynamic client registration to loopback redirect URIs by @xernobyl in #9300
  • fix(i18n): unify the Japanese term for Survey and translate the strings left in English [ENG-2393] by @Dhruwang in #9308
  • fix(i18n): translate the team permission label, membership status badges and organization roles [ENG-2481] by @Dhruwang in #9309
  • fix(surveys): strip trailing colon from validation field labels [ENG-1797] by @Dhruwang in #9311
  • fix(responses): keep a column labelled __proto__ in the export by @itsjavi in #9315
  • fix(storage): delete workspace files when an organization or account is deleted [ENG-3197] by @pandeymangg in #9316
  • fix(security): gate API key organization write access at mint time by @pandeymangg in #9317
  • fix(account): send a relative callbackURL on the SSO account-deletion link by @xernobyl in #9318
  • fix(auth): look users up by the canonical email address by @xernobyl in #9319
  • fix(surveys): address respondents formally in the German and Russian survey UI by @mattinannt in #9321
  • fix(storage): delete the old logo file when a workspace logo is removed or replaced [ENG-2418] by @pandeymangg in #9322
  • fix(editor): seed the rich text editor once per mount, not twice by @xernobyl in #9328
  • fix(deps): raise the fast-xml-parser floor to 5.7.2 so S3 XML responses parse [ENG-3263] by @pandeymangg in #9329
  • fix(js-core): hold the survey concurrency guard once a survey has rendered (ENG-2849) by @pandeymangg in #9331
  • fix(auth): keep logout on the admin domain when PUBLIC_URL is set [ENG-3286] by @jobenjada in #9333
  • fix(helm): make v6 upgrades safer for self-hosters by @BhagyaAmarasinghe in #9339
  • fix(unify-feedback): pluralize feedback-record counts in the records table [ENG-2606] by @Dhruwang in #9343
  • fix(unify-feedback): keep a held Enter to a single dataset purge [ENG-2604] by @Dhruwang in #9345
  • fix(survey-link): serve a same-script sibling for a requested survey language [ENG-3083] by @Dhruwang in #9353
  • fix(security): make the fresh-instance sign-up exception single-use [ENG-2247] by @pandeymangg in #9354
  • fix(ui): give link-buttons a hover state [ENG-3138] by @Dhruwang in #9355
  • fix(auth): name what the MCP feedbackRecords:write scope grants [ENG-3192] by @Dhruwang in #9356
  • fix(auth): stop serving Better Auth’s /update-user over HTTP [ENG-3189] by @Dhruwang in #9358
  • fix(analysis): resolve date presets in the organization’s time zone on summary and charts [ENG-3215] by @itsjavi in #9361
  • fix: refund failed invite rate-limit usage by @BhagyaAmarasinghe in #9362
  • fix(surveys): close the language switcher on Escape and return focus to its trigger by @Dhruwang in #9365
  • fix(i18n): use Unicode punctuation and remove contractions in English copy by @Dhruwang in #9367
  • fix(workspace-settings): disable manage-gated settings for read/write members [ENG-3191] by @itsjavi in #9368
  • fix(auth): unlock password users whose credential row has no issuer [ENG-3258] by @pandeymangg in #9369
  • fix: correct doesNotIncludeAllOf, surface impressions load errors, delete removed survey languages by @mattinannt in #9371
  • fix(sso): revoke the squatter’s API keys on SSO recovery by @pandeymangg in #9372
  • fix(surveys): open each cardless survey page at the top [ENG-3379] by @Dhruwang in #9374
  • fix(surveys): stop naming survey images and name inline surveys [ENG-3154] by @itsjavi in #9376
  • fix(web): single-brand link survey titles and render ICU placeholders [ENG-3154] by @itsjavi in #9377
  • fix(editor): group question types and clear settings tab axe violations [ENG-3154] by @itsjavi in #9378
  • fix(docker): run hub worker in self-hosted compose by @BhagyaAmarasinghe in #9379
  • fix(analysis): thin and relabel time axes for hourly granularity [ENG-3211] by @itsjavi in #9380
  • fix(survey-ui): keep out-of-month date picker days at full contrast [ENG-1296] by @itsjavi in #9381
  • fix(mcp): log JWKS load failures as jwks_fetch by @jobenjada in #9382
  • fix(integrations): show a reconnect message when Google Sheets lacks the scope [ENG-2807] by @Dhruwang in #9383
  • fix(ai-translation): explain output token limit overflow instead of a generic failure [ENG-2831] by @Dhruwang in #9384
  • fix(surveys): only ring the close and language buttons on keyboard focus [ENG-1830] by @itsjavi in #9385
  • fix(settings): hide the integrations tip when the user has no workspace [ENG-1781] by @Dhruwang in #9387
  • fix(dashboards): add new charts to the next open slot [ENG-3209] by @Dhruwang in #9390
  • fix(helm): prevent TEI API key logging by @BhagyaAmarasinghe in #9391
  • fix: rate-limit AI chart generation by @BhagyaAmarasinghe in #9392
  • fix: replace MinIO client with RustFS CLI by @BhagyaAmarasinghe in #9395
  • fix: sanitize v1 contact list database errors by @BhagyaAmarasinghe in #9396
  • fix(surveys): require a valid web address for ending card button and redirect URLs [ENG-2585] by @Dhruwang in #9399
  • fix(audit): keep respondent content out of the audit log, and record refused MCP mutations by @pandeymangg in #9402
  • fix(surveys): pin —spacing inside #fbjs against host overrides [ENG-833] by @itsjavi in #9405
  • fix(analysis): reject nonsensical prompts in AI chart generation [ENG-3210] by @itsjavi in #9406
  • fix(database): harden postgres connection reliability by @BhagyaAmarasinghe in #9407
  • fix(survey-list): keep settings when a survey is duplicated [ENG-2144] by @pandeymangg in #9409
  • fix(survey): reject JSON literals as numeric prefill values (ENG-1146) by @Dhruwang in #9410
  • fix(web): typecheck Playwright specs in pnpm typecheck [ENG-2239] by @itsjavi in #9413
  • fix(telemetry): send usage updates through the configured HTTPS_PROXY by @Dhruwang in #9414
  • fix(charts): scale the flipped category gutter with the chart width [ENG-3223] by @Dhruwang in #9418
  • fix(surveys): drop image minimum height once media has loaded [ENG-3421] by @Dhruwang in #9420
  • fix(surveys): use “Skicka in” for the Swedish submit button by @jobenjada in #9422
  • fix(api): bound request arrays and cap invalid_params on v3 and MCP [ENG-3384] by @pandeymangg in #9423
  • fix(web): validate brandColor before it reaches the OG image SVG [ENG-2563] by @itsjavi in #9425
  • fix(web): attribute Sentry errors to the signed-in user by id [ENG-2326] by @itsjavi in #9426
  • fix: block 10 personal email domains on Cloud by @jobenjada in #9427
  • fix(storage): delete respondent uploads when a survey is deleted [ENG-3373] by @pandeymangg in #9428
  • fix(web): require Manage access to change survey custom head scripts by @mattinannt in #9432
  • fix(surveys): 44px close button touch area, inset from the card corner [ENG-3429] (a11y) by @itsjavi in #9433
  • fix(survey-editor): name the block, not its id, when a logic destination is gone [ENG-3443] by @itsjavi in #9440
  • fix(security): bump nodemailer, undici, fast-uri and ip-address and patch 8 advisories [ENG-3435][ENG-3442] by @Dhruwang in #9444
  • fix(survey-editor): stop recall tag edits hanging the editor in an update loop [ENG-2931] by @Dhruwang in #9447
  • fix(helm): render containerSecurityContext on the web container [ENG-2922] by @BhagyaAmarasinghe in #9450
  • fix(helm): validate the two cross-process taxonomy timing invariants [ENG-2813] by @BhagyaAmarasinghe in #9451
  • fix(docker): ship a slim Cube image without known CVEs [ENG-3431] by @BhagyaAmarasinghe in #9457
  • fix(helm): run Cube with a read-only root filesystem and no capabilities by @BhagyaAmarasinghe in #9461
  • fix(security): bump markdown-it, engine.io and brace-expansion and patch 6 advisories [ENG-3463][ENG-3462][ENG-3461][ENG-3460][ENG-3459][ENG-3458] by @Dhruwang in #9462
  • fix(taxonomy): wire TAXONOMY_MAX_RECORDS in compose and fail fast on empty LLM base URL [ENG-1522] by @BhagyaAmarasinghe in #9463
  • fix(billing): replace legacy EUR subscriptions instead of swapping USD prices onto them by @Dhruwang in #9464
  • fix(settings): keep a workspace-less organization active in account settings by @Dhruwang in #9465
  • fix(helm): harden the migration Job’s containers [ENG-3480] by @BhagyaAmarasinghe in #9468
  • fix(analysis): translate response filter criteria [ENG-645] by @Dhruwang in #9470
  • fix(auth): revoke an OAuth app’s tokens when its consent is revoked by @xernobyl in #9472
  • fix(responses): fold a contact’s identical resubmission within a minute into the first response by @Dhruwang in #9477
  • fix(deps): bump next to 16.3.6 for GHSA-vcvr-r3jv-pc5j by @Dhruwang in #9478
  • fix: restrict survey reset to workspace managers by @jobenjada in #9480
  • fix(i18n): translate 76 strings left in English in 12 locales by @xernobyl in #9486
  • fix(docker): rebuild the Cube image on the fixed distroless base (1.7.47-2) by @BhagyaAmarasinghe in #9492
  • fix(auth): let claude.ai and ChatGPT MCP connectors register through DCR by @xernobyl in #9494
  • fix(contacts): derive activity timeline read-only state on the server by @mattinannt in #9495
  • fix(database): stop write transactions expiring on Prisma’s 5 s default [ENG-3285] by @xernobyl in #9499
  • fix(api-v3): refuse NULL bytes in list filters and cursors with a 400 by @xernobyl in #9501
  • fix(helm): restore writable migration jobs for older images by @BhagyaAmarasinghe in #9503
  • fix(security): bump hono to 4.13.7 and patch 1 advisory [ENG-3486] by @Dhruwang in #9505
  • fix(docker): pin basic-ftp 6.2.2 in the Cube image for CVE-2026-102990 (1.7.47-3) by @Dhruwang in #9506
  • fix(setup): fit the setup forms inside their card on narrow screens by @Dhruwang in #9507
  • fix(storage): delete removed-element uploads by their survey-scoped key [ENG-2546] by @pandeymangg in #9509
  • fix(survey-editor): mount the workspace context in the editor layout [ENG-2601] by @pandeymangg in #9510
  • fix(web): tell the user when a server action gets an unexpected response [ENG-2899] by @xernobyl in #9513
  • fix(helm): set numeric UID for AuthZed hooks by @BhagyaAmarasinghe in #9516
  • fix(contacts): bind bulk-upload attribute-key arrays as typed text[] params [ENG-3549] by @Dhruwang in #9520
  • fix(og): leave right-to-left survey names off the preview card by @pandeymangg in #9521
  • fix(charts): drop option-less groups from charts grouped by value option by @Dhruwang in #9523
  • fix(survey-link): stop a superseded language switch landing after the respondent moved on [ENG-3170] by @Dhruwang in #9524
  • fix(hub): stop passing Next’s proxied request to the Request constructor in the feedback-records dev proxy [ENG-3225] by @xernobyl in #9525
  • fix(gateway): refuse ambiguous JSON bodies before authorizing feedback records [ENG-3658] by @xernobyl in #9532
  • fix(surveys): give unnamed pop-up surveys a top-level heading by @itsjavi in #9533
  • fix(segments): let interaction filters target the survey being edited by @jobenjada in #9534
  • fix(security): bump source-map-js to 1.2.2 and patch 1 advisory [ENG-3661] by @Dhruwang in #9536
  • fix(docs): point anchor links at Mintlify heading ids by @jobenjada in #9540
  • fix(web): report a rejected clipboard write instead of a false “Copied” toast [ENG-3239] by @Dhruwang in #9542
  • fix(ai): stop logging prompts and model output when an AI call fails [ENG-3720] by @xernobyl in #9550
  • fix(responses): read organization and contact before the management create transactions [ENG-3722] by @xernobyl in #9551
  • fix(web): drop inert Access-Control-Allow-Credentials from public client API CORS by @pandeymangg in #9553
  • fix: remediate Formbricks image vulnerabilities by @BhagyaAmarasinghe in #9558
  • fix(billing): charge VAT through Stripe automatic tax on paid plans by @Dhruwang in #9568
  • fix(web): allow blob: workers in the CSP so Sentry Replay can compress by @pandeymangg in #9573
  • fix(teams): expire pending invites when their creator leaves the organization by @BhagyaAmarasinghe in #9576
  • fix(security): bump next to 16.3.8 and patch 2 advisories [ENG-3737][ENG-3743] by @Dhruwang in #9579
  • fix(database): build the keyset Response indexes with lock_timeout = 0 [ENG-3701] by @BhagyaAmarasinghe in #9580
  • fix(docker): reset install-input timestamps after the source copy so a cached install passes pnpm’s check [ENG-3801] by @xernobyl in #9581
  • fix(deps): pin handlebars 4.7.10 and shell-quote 1.12.0 for critical advisories [ENG-3806] by @xernobyl in #9584
  • fix(invites): limit invites per user and org creation, bound inviter name by @mattinannt in #9585
  • fix(survey-link): give link survey routes their own error boundary [ENG-3171] by @pandeymangg in #9586
  • fix: create Dependabot Linear tickets as vulnerability-labelled Triage items by @mattinannt in #9589
  • fix(auth): keep the OAuth state cookie alive as long as the state it guards [ENG-3314] by @xernobyl in #9600
  • fix: page survey summary and response export in sort order by @itsjavi in #9601
  • fix(database): keep the legacy Survey columns until Formbricks 7 by @pandeymangg in #9603
  • fix(database): make the idle-transaction backstop opt-in through DATABASE_URL [ENG-3285] by @xernobyl in #9604
  • fix(docker): warn instead of blocking when the Compose is missing hub-worker [ENG-2484] by @xernobyl in #9606
  • fix(surveys): keep renderer line-heights unitless so iOS Dynamic Type scales them once by @itsjavi in #9608
  • fix: keep Next.js server and browser assets in sync by @BhagyaAmarasinghe in #9614
  • fix(survey-ui): keep smiley rating line art readable in dark mode [ENG-3937] by @Dhruwang in #9626
  • fix: sign Plain chat external ID with customerDetailsSignature (backport #9628 to release/6.1) by @Dhruwang in #9630
  • fix(api-v3): refuse survey patches and block edits that introduce cyclic logic by @Dhruwang in #9634
  • fix(surveys): resolve bare language codes to the canonical survey language [ENG-3961] by @itsjavi in #9637
  • fix: run the JS SDK journey under a customer CSP and stop Zod’s eval probe [ENG-3969] by @Dhruwang in #9640
  • fix(helm): skip deferred migrations in the Hub migration wait [ENG-3948] by @BhagyaAmarasinghe in #9642
  • fix(docker): refresh the bundled Cube model on update [ENG-3951] by @BhagyaAmarasinghe in #9645
  • fix(authzed): document the prepare Job’s full environment and name invalid variables [ENG-3953] by @BhagyaAmarasinghe in #9650
  • fix(api-v3): accept survey patches that leave a stored survey’s existing issues untouched [ENG-3975] by @Dhruwang in #9651
  • fix(workspaces): enforce the workspace limit inside the creating transaction (backport #9613 to release/6.1) [ENG-3921] by @xernobyl in #9654
  • fix(upgrade): run the online migration script from the bundled CLI’s image path [ENG-3949] by @BhagyaAmarasinghe in #9656
  • fix(upgrade): compare survey edges as sets in online finalize [ENG-3950] by @BhagyaAmarasinghe in #9662
  • fix(chart): let online mode keep a single Cube replica [ENG-3955] by @BhagyaAmarasinghe in #9663
  • fix(surveys): keep every answer when file uploads overlap [ENG-3945] (backport #9672 to release/6.1) by @pandeymangg in #9674

🔧 Refactors

  • refactor(api-v3): consolidate error handling into one thrown-error mapper, one Hub mapper and a problem-code registry by @xernobyl in #9147
  • refactor(mcp): put the feedback-record tools back on registerScopedTool by @xernobyl in #9290
  • refactor(auth): make BETTER_AUTH_* the documented env var names, keep NEXTAUTH_* as an alias by @xernobyl in #9307
  • refactor(api-v3): one shared list meta across the v3 collection endpoints by @pandeymangg in #9336
  • refactor: clear AuthZed cutover SonarQube findings by @BhagyaAmarasinghe in #9452
  • refactor(web): keep service modules server-only and guard “use server” exports by @mattinannt in #9497
  • refactor(api-v3): generate the Responses Zod schemas from the OpenAPI spec by @xernobyl in #9500
  • refactor(surveys): pull the block-flow decision out of the survey component by @mattinannt in #9531
  • refactor(hub): adopt @formbricks/hub 0.14.0 and drop the query-serialization workaround [ENG-2536] by @xernobyl in #9594

⚡ Performance

  • perf(survey-editor): debounce preview updates while editing [ENG-991] by @itsjavi in #9370
  • perf(survey-editor): memoize block cards to skip unchanged blocks on edit [ENG-992] by @itsjavi in #9373
  • perf(docker): shrink the build context and cache the install layer [ENG-587] by @BhagyaAmarasinghe in #9466

📚 Docs

  • docs: rename Connect Your App to Web & Mobile SDK, document install methods by @jobenjada in #9168
  • docs(review): make performance an explicit review dimension (ENG-3179) by @Dhruwang in #9251
  • docs: add release and maintenance policy page by @mattinannt in #9273
  • docs: add Okta OIDC setup guide by @jobenjada in #9275
  • docs: clarify Kubernetes v6 maintenance upgrades by @BhagyaAmarasinghe in #9282
  • docs: move AuthZed Operations, Rate Limiting and AI Features into Configuration by @jobenjada in #9306
  • docs: correct the conformance claims on the accessibility page by @jobenjada in #9348
  • docs: inline local setup instructions by @mattinannt in #9359
  • docs: forbid agent session links in PRs and commits by @itsjavi in #9388
  • docs: add performance testing guidance by @BhagyaAmarasinghe in #9408
  • docs: add workspaceSurveyCount to the MCP list_surveys example by @pandeymangg in #9417
  • docs: remove leftover merge-conflict marker from v6 migration guide by @BhagyaAmarasinghe in #9458
  • docs: add Attio and Salesforce integration guides by @harshsbhat in #9473
  • docs(mcp): add an Adding A Tool guide to the MCP handbook by @xernobyl in #9481
  • docs(self-hosting): say which patch releases carry the bundled Cube image by @BhagyaAmarasinghe in #9491
  • docs: fix dead links, stray anchors and an unclosed div in the readme by @pandeymangg in #9528
  • docs: correct how Prisma applies migrations and document failed-migration recovery [ENG-2820] by @xernobyl in #9529
  • docs(mcp): troubleshoot Cloudflare blocking self-hosted MCP connections by @BhagyaAmarasinghe in #9554
  • docs: mark the 5.4 accessibility fixes as released by @jobenjada in #9597
  • docs: remove v6.1 section from the self-hosting migration guide by @mattinannt in #9599
  • docs(self-hosting): pin Cube by digest on 6.0.x before an online upgrade by @Dhruwang in #9658

⚙️ CI

  • fix(ci): pull the MinIO images from quay.io instead of Docker Hub by @xernobyl in #9260
  • chore(ci): stop inheriting secrets into the PR gate’s reusable workflows by @pandeymangg in #9330
  • feat(ci): sync the release-branch cut to Linear by @mattinannt in #9346
  • chore(ci): add Dependabot for GitHub Actions and unify harden-runner pins (ENG-2544) by @Dhruwang in #9411
  • chore(ci): retire orphaned Formbricks Cloud helmfile deploy workflow by @BhagyaAmarasinghe in #9442
  • fix(ci): scan the published release image by digest instead of a dead workflow_run trigger by @BhagyaAmarasinghe in #9443
  • fix(ci): stop maintenance releases rolling GHCR major/minor tags back [ENG-2926] by @BhagyaAmarasinghe in #9449
  • fix(ci): exclude nested lockfiles from the PR size check by @BhagyaAmarasinghe in #9459
  • fix(ci): fail the latest-release check closed instead of promoting on API errors [ENG-2927] by @xernobyl in #9496
  • chore(ci): bump the github-actions group across 4 directories with 24 updates by @mattinannt in #9522

🧹 Chores

  • chore: A/B test shortening the Pro trial from 14 to 7 days by @harshsbhat in #9224
  • chore(eslint): widen the package lint gates past ./src by @xernobyl in #9286
  • chore(sonar): enrol eight packages and the route/action layer in coverage [ENG-2432] by @Dhruwang in #9310
  • chore(deps): replace the deprecated otplib 12 and @react-email/components by @Dhruwang in #9313
  • test(attachments): stop the headers test leaking its stream into the next test by @itsjavi in #9314
  • chore(api-v3): mark the generated OpenAPI bundle linguist-generated by @mattinannt in #9349
  • chore(i18n): drop the retroactivity sentence from the anonymize toggle by @jobenjada in #9357
  • chore: update Helm app version to 6.0.0 by @BhagyaAmarasinghe in #9366
  • chore(email): map react-email components for jsx-a11y [ENG-3154] by @itsjavi in #9375
  • chore: dedupe lockfile and clean up stale repository configuration by @mattinannt in #9400
  • test: run repo-level script tests as part of pnpm test by @xernobyl in #9469
  • chore(billing): ship the trial and response-limit nudges to everyone by @harshsbhat in #9471
  • chore: align Node 24 across CI, engines and the devcontainer by @xernobyl in #9474
  • chore(deps): bump Prisma to 7.10.0 to fix leaked transactions after a maxWait overrun by @xernobyl in #9498
  • test(billing): cover subscription_cancelled on both plan-downgrade paths by @Dhruwang in #9527
  • chore(sentry): drop scanner multipart noise at ingest [ENG-1745] by @pandeymangg in #9537
  • chore: remove CODEOWNERS and automatic PR reviewer assignment by @mattinannt in #9590
  • chore(docker): bump the cube group in /docker/cube-image with 2 updates by @Dhruwang in #9605

🔒 Security credits

Thanks to the following researchers, who reported issues fixed in this release through responsible disclosure:
  • Kareem Mahmoud — concurrent requests could create workspaces past the plan’s workspace limit (#9654)
Full Changelog: https://github.com/formbricks/formbricks/compare/6.0.2…6.1.0