[GH-ISSUE #8307] teamId missing in return object of auth.api.getFullOrganization() #11052

Open
opened 2026-04-13 07:25:46 -05:00 by GiteaMirror · 5 comments
Owner

Originally created by @DarkNasuada on GitHub (Mar 2, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/8307

Originally assigned to: @himself65 on GitHub.

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

enable Teams
add member to team
request fullorganizationaldata

Current vs. Expected behavior

i expected to get the teamId in the members object as stated in the type from the return object,
poperty teamId is completely missing.

What version of Better Auth are you using?

latest

System info

{
  "system": {
    "platform": "win32",
    "arch": "x64",
    "version": "Windows 11 Pro",
    "release": "10.0.26100",
    "cpuCount": 28,
    "cpuModel": "Intel(R) Core(TM) i7-14700",
    "totalMemory": "31.68 GB",
    "freeMemory": "8.06 GB"
  },
  "node": {
    "version": "v25.6.1",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.9.0"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "^16.1.6"
    },
    {
      "name": "react",
      "version": "^19.2.4"
    }
  ],
  "databases": null,
  "betterAuth": {
    "version": "^1.4.19",
    "config": null
  }
}

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

import { betterAuth } from 'better-auth'
import { nextCookies } from 'better-auth/next-js'
import { admin } from 'better-auth/plugins/admin'
import { organization } from 'better-auth/plugins/organization'
import { magicLink } from 'better-auth/plugins/magic-link'
import { appAccessControl, organizationRoles } from './permissions'
import { MssqlDialect } from 'kysely'
import * as Tedious from 'tedious'
import * as Tarn from 'tarn'
import { sendMail } from '../msGraph'
import { APIError } from 'better-auth/api'

const dialect = new MssqlDialect({
	tarn: {
		...Tarn,
		options: {
			min: 0,
			max: 10,
		},
	},
	tedious: {
		...Tedious,
		TYPES: {
			...Tedious.TYPES,
			DateTime: Tedious.TYPES.DateTime2,
		},
		connectionFactory: () =>
			new Tedious.Connection({
				authentication: {
					type: 'default',
					options: {
						userName: process.env.DB_USER,
						password: process.env.DB_PASS,
					},
				},
				server: process.env.DB_HOST,
				options: {
					database: process.env.DB_NAME,	
					port: 1433,
					trustServerCertificate: true,
					encrypt: false,
				},
			}),
	},
})

export const auth = betterAuth({
	experimental: { joins: true },
	baseURL: process.env.BETTER_AUTH_URL,
	secret: process.env.BETTER_AUTH_SECRET,
	database: {
		dialect,
		type: 'mssql',
	},
	databaseHooks: {
		session: {
			create: {
				before: async (session, context) => {
					if (!context || session.activeOrganizationId) {
						return
					}

					const adapter = context.context.adapter
					const memberships = await adapter.findMany<{ organizationId: string }>({
						model: 'member',
						where: [
							{
								field: 'userId',
								value: session.userId,
							},
						],
						sortBy: {
							field: 'createdAt',
							direction: 'asc',
						},
						limit: 1,
					})

					const membership = memberships[0]

					let activeTeamId: string | null = null

					const teamMemberships = await adapter.findMany<{ teamId: string; team?: { organizationId?: string | null } | null }>({
						model: 'teamMember',
						where: [
							{
								field: 'userId',
								value: session.userId,
							},
						],
						join: { team: true },
						sortBy: {
							field: 'createdAt',
							direction: 'asc',
						},
					})

					const matchingTeamMembership = teamMemberships.find((teamMembership) => teamMembership.team?.organizationId === membership.organizationId)

					if (matchingTeamMembership) {
						activeTeamId = matchingTeamMembership.teamId
						//add retrieval of team roles here and add to session if found
					}
					return {
						data: {
							...session,
							activeOrganizationId: membership.organizationId,
							activeTeamId: activeTeamId || '',
						},
					}
				},
			},
		},
		// user: {
		// 	create: {
		// 		before: async (user, context) => {
		// 			if (!context) return
		// 			//prevent creation of user accounts that are not invited by an organization member
		// 			const adapter = context.context.adapter
		// 			const invitations = await adapter.findMany({
		// 				model: 'invitation',
		// 				where: [
		// 					{
		// 						field: 'email',
		// 						value: user.email,
		// 					},
		// 				],
		// 				sortBy: {
		// 					field: 'createdAt',
		// 					direction: 'desc',
		// 				},
		// 				limit: 1,
		// 			})
		// 			if (invitations.length === 0) {
		// 				throw new APIError(403, { message: 'Er is geen uitnodiging gevonden voor dit e-mailadres. Neem contact op met de beheerder van je organisatie om een uitnodiging te ontvangen.' })
		// 			}
		// 		},
		// 	},
		// },
	},
	trustedOrigins: [process.env.NEXT_PUBLIC_SITE_URL].filter((origin): origin is string => !!origin),
	rateLimit: {
		enabled: true,
	},
	plugins: [
		nextCookies(),
		admin({
			defaultRole: 'user',
			adminRoles: ['admin'],
		}),
		organization({
			allowUserToCreateOrganization: false,
			ac: appAccessControl,
			roles: organizationRoles,
			teams: {
				enabled: true,
				allowRemovingAllTeams: false,
			},
			schema: {
				team: {
					additionalFields: {
						customerNumber: {
							type: 'string',
							required: true,
							unique: true,
						},
					},
				},
			},
		}),
		magicLink({
			disableSignUp: true,
			sendMagicLink: async ({ email, url }, ctx) => {
	
				const recipientList: Parameters<typeof sendMail>[3] = [{ emailAddress: { address: email } }]
				await sendMail('Aanmelden via magic link', 'html', `<p>Klik op onderstaande link om in te loggen.</p><p><a href="${url}">Inloggen</a></p>`, recipientList)
			},
			expiresIn: 60 * 15,
		}),
	],
	socialProviders: {
		microsoft: {
			clientId: process.env.AZURE_AD_CLIENT_ID,
			clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
			tenantId: process.env.AZURE_AD_TENANT_ID,
			scope: ['openid', 'profile', 'email', 'User.Read', 'offline_access'],
		},
	},
})

export type AuthSession = typeof auth.$Infer.Session
export type FullOrgData = Exclude<Awaited<ReturnType<typeof auth.api.getFullOrganization>>, null>
export type TeamsData = NonNullable<FullOrgData>['teams']

Additional context

No response

Originally created by @DarkNasuada on GitHub (Mar 2, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/8307 Originally assigned to: @himself65 on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce enable Teams add member to team request fullorganizationaldata ### Current vs. Expected behavior i expected to get the teamId in the members object as stated in the type from the return object, poperty teamId is completely missing. ### What version of Better Auth are you using? latest ### System info ```bash { "system": { "platform": "win32", "arch": "x64", "version": "Windows 11 Pro", "release": "10.0.26100", "cpuCount": 28, "cpuModel": "Intel(R) Core(TM) i7-14700", "totalMemory": "31.68 GB", "freeMemory": "8.06 GB" }, "node": { "version": "v25.6.1", "env": "development" }, "packageManager": { "name": "npm", "version": "11.9.0" }, "frameworks": [ { "name": "next", "version": "^16.1.6" }, { "name": "react", "version": "^19.2.4" } ], "databases": null, "betterAuth": { "version": "^1.4.19", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from 'better-auth' import { nextCookies } from 'better-auth/next-js' import { admin } from 'better-auth/plugins/admin' import { organization } from 'better-auth/plugins/organization' import { magicLink } from 'better-auth/plugins/magic-link' import { appAccessControl, organizationRoles } from './permissions' import { MssqlDialect } from 'kysely' import * as Tedious from 'tedious' import * as Tarn from 'tarn' import { sendMail } from '../msGraph' import { APIError } from 'better-auth/api' const dialect = new MssqlDialect({ tarn: { ...Tarn, options: { min: 0, max: 10, }, }, tedious: { ...Tedious, TYPES: { ...Tedious.TYPES, DateTime: Tedious.TYPES.DateTime2, }, connectionFactory: () => new Tedious.Connection({ authentication: { type: 'default', options: { userName: process.env.DB_USER, password: process.env.DB_PASS, }, }, server: process.env.DB_HOST, options: { database: process.env.DB_NAME, port: 1433, trustServerCertificate: true, encrypt: false, }, }), }, }) export const auth = betterAuth({ experimental: { joins: true }, baseURL: process.env.BETTER_AUTH_URL, secret: process.env.BETTER_AUTH_SECRET, database: { dialect, type: 'mssql', }, databaseHooks: { session: { create: { before: async (session, context) => { if (!context || session.activeOrganizationId) { return } const adapter = context.context.adapter const memberships = await adapter.findMany<{ organizationId: string }>({ model: 'member', where: [ { field: 'userId', value: session.userId, }, ], sortBy: { field: 'createdAt', direction: 'asc', }, limit: 1, }) const membership = memberships[0] let activeTeamId: string | null = null const teamMemberships = await adapter.findMany<{ teamId: string; team?: { organizationId?: string | null } | null }>({ model: 'teamMember', where: [ { field: 'userId', value: session.userId, }, ], join: { team: true }, sortBy: { field: 'createdAt', direction: 'asc', }, }) const matchingTeamMembership = teamMemberships.find((teamMembership) => teamMembership.team?.organizationId === membership.organizationId) if (matchingTeamMembership) { activeTeamId = matchingTeamMembership.teamId //add retrieval of team roles here and add to session if found } return { data: { ...session, activeOrganizationId: membership.organizationId, activeTeamId: activeTeamId || '', }, } }, }, }, // user: { // create: { // before: async (user, context) => { // if (!context) return // //prevent creation of user accounts that are not invited by an organization member // const adapter = context.context.adapter // const invitations = await adapter.findMany({ // model: 'invitation', // where: [ // { // field: 'email', // value: user.email, // }, // ], // sortBy: { // field: 'createdAt', // direction: 'desc', // }, // limit: 1, // }) // if (invitations.length === 0) { // throw new APIError(403, { message: 'Er is geen uitnodiging gevonden voor dit e-mailadres. Neem contact op met de beheerder van je organisatie om een uitnodiging te ontvangen.' }) // } // }, // }, // }, }, trustedOrigins: [process.env.NEXT_PUBLIC_SITE_URL].filter((origin): origin is string => !!origin), rateLimit: { enabled: true, }, plugins: [ nextCookies(), admin({ defaultRole: 'user', adminRoles: ['admin'], }), organization({ allowUserToCreateOrganization: false, ac: appAccessControl, roles: organizationRoles, teams: { enabled: true, allowRemovingAllTeams: false, }, schema: { team: { additionalFields: { customerNumber: { type: 'string', required: true, unique: true, }, }, }, }, }), magicLink({ disableSignUp: true, sendMagicLink: async ({ email, url }, ctx) => { const recipientList: Parameters<typeof sendMail>[3] = [{ emailAddress: { address: email } }] await sendMail('Aanmelden via magic link', 'html', `<p>Klik op onderstaande link om in te loggen.</p><p><a href="${url}">Inloggen</a></p>`, recipientList) }, expiresIn: 60 * 15, }), ], socialProviders: { microsoft: { clientId: process.env.AZURE_AD_CLIENT_ID, clientSecret: process.env.AZURE_AD_CLIENT_SECRET, tenantId: process.env.AZURE_AD_TENANT_ID, scope: ['openid', 'profile', 'email', 'User.Read', 'offline_access'], }, }, }) export type AuthSession = typeof auth.$Infer.Session export type FullOrgData = Exclude<Awaited<ReturnType<typeof auth.api.getFullOrganization>>, null> export type TeamsData = NonNullable<FullOrgData>['teams'] ``` ### Additional context _No response_
GiteaMirror added the organization label 2026-04-13 07:25:46 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Mar 2, 2026):

This is expected behavior in Better Auth 1.3+, though I agree the TypeScript types are misleading here.

Why teamId is missing: In v1.3, Better Auth moved to a many-to-many team membership model using a separate teamMember join table. The member table no longer has a teamId column, and getFullOrganization doesn't join with teamMember, so it can't populate that field.

Workaround: To get team membership data, use the dedicated team APIs:

  • GET /organization/list-user-teams - get teams for a specific user
  • POST /organization/list-team-members - get members of a specific team

That said, the type definition does show teamId as an optional field when teams are enabled, which is confusing since it's never actually populated by getFullOrganization. This could be considered a documentation/type bug worth addressing.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3987449151 --> @dosubot[bot] commented on GitHub (Mar 2, 2026): <!-- Answer --> This is expected behavior in Better Auth 1.3+, though I agree the TypeScript types are misleading here. **Why `teamId` is missing:** In v1.3, Better Auth [moved to a many-to-many team membership model](https://better-auth.com/blog/1-3) using a separate `teamMember` join table. The `member` table no longer has a `teamId` column, and [`getFullOrganization` doesn't join with `teamMember`](https://github.com/better-auth/better-auth/blob/35deabdef026f6887eb5dfda539f39460076fad4/packages/better-auth/src/plugins/organization/adapter.ts#L497-L584), so it can't populate that field. **Workaround:** To get team membership data, use the dedicated team APIs: - `GET /organization/list-user-teams` - get teams for a specific user - `POST /organization/list-team-members` - get members of a specific team That said, the [type definition does show `teamId` as an optional field](https://github.com/better-auth/better-auth/blob/35deabdef026f6887eb5dfda539f39460076fad4/packages/better-auth/src/plugins/organization/schema.ts#L400-L420) when teams are enabled, which is confusing since it's never actually populated by `getFullOrganization`. This could be considered a documentation/type bug worth addressing. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/934e93ea-d46c-4361-9218-675eb2765eb1?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/934e93ea-d46c-4361-9218-675eb2765eb1?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/934e93ea-d46c-4361-9218-675eb2765eb1?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/934e93ea-d46c-4361-9218-675eb2765eb1?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/934e93ea-d46c-4361-9218-675eb2765eb1?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/934e93ea-d46c-4361-9218-675eb2765eb1?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/934e93ea-d46c-4361-9218-675eb2765eb1?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20is%20expected%20behavior%20in%20Better%20Auth%201.3%2B%2C%20though%20I%20agree%20the%20TypeScript%20types%20are%20misleading%20here.%0A%0A%2A%2AWhy%20%60teamId%60%20is%20missing%3A%2A%2A%20In%20v1.3%2C%20Better%20Auth%20%5Bmoved%20to%20a%20many-to-many%20team%20membership%20model%5D%28https%3A//better-auth.com/blog/1-3%29%20using%20a%20separate%20%60teamMember%60%20join%20table.%20The%20%60member%60%20table%20no%20longer%20has%20a%20%60teamId%60%20column%2C%20and%20%5B%60getFullOrganization%60%20doesn%27t%20join%20with%20%60teamMember%60%5D%28https%3A//github.com/better-auth/better-auth/blob/35deabdef026f6887eb5dfda539f39460076fad4/packages/better-auth/src/plugins/organization/adapter.ts%23L497-L584%29%2C%20so%20it%20can%27t%20populate%20that%20field.%0A%0A%2A%2AWorkaround%3A%2A%2A%20To%20get%20team%20membership%20data%2C%20use%20the%20dedicated%20team%20APIs%3A%0A-%20%60GET%20/organization/list-user-teams%60%20-%20get%20teams%20for%20a%20specific%20user%0A-%20%60POST%20/organization/list-team-members%60%20-%20get%20members%20of%20a%20specific%20team%0A%0AThat%20said%2C%20the%20%5Btype%20definition%20does%20show%20%60teamId%60%20as%20an%20optional%20field%5D%28https%3A//github.com/better-auth/better-auth/blob/35deabdef026f6887eb5dfda539f39460076fad4/packages/better-auth/src/plugins/organization/schema.ts%23L400-L420%29%20when%20teams%20are%20enabled%2C%20which%20is%20confusing%20since%20it%27s%20never%20actually%20populated%20by%20%60getFullOrganization%60.%20This%20could%20be%20considered%20a%20documentation/type%20bug%20worth%20addressing.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8307)
Author
Owner

@DarkNasuada commented on GitHub (Mar 2, 2026):

@dosu when querying full organization data and i get organization data, members data and a full teamslist but without the teamid at the member there is no way to properly use the data. in a relational manor. so i consider this a bug in the code and not a type mistake

<!-- gh-comment-id:3987478154 --> @DarkNasuada commented on GitHub (Mar 2, 2026): @dosu when querying full organization data and i get organization data, members data and a full teamslist but without the teamid at the member there is no way to properly use the data. in a relational manor. so i consider this a bug in the code and not a type mistake
Author
Owner

@dosubot[bot] commented on GitHub (Mar 2, 2026):

You raise a valid point. Looking at the code more closely, you're right that this is a functional gap rather than just a type issue.

The getFullOrganization response returns members[], teams[], and invitations[] as separate arrays with no relational data connecting them. The teamMember junction table exists in the database schema and stores the team-member relationships, but the findFullOrganization adapter method simply doesn't query or include this data.

So you get all the pieces but no way to connect them—which defeats much of the purpose of a "full organization" response. This does seem like a reasonable feature request/bug: either include teamMembers[] in the response, add a teams array to each member, or add a members array to each team.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3987486555 --> @dosubot[bot] commented on GitHub (Mar 2, 2026): <!-- Answer --> You raise a valid point. Looking at the code more closely, you're right that this is a functional gap rather than just a type issue. The [`getFullOrganization` response](https://github.com/better-auth/better-auth/blob/35deabdef026f6887eb5dfda539f39460076fad4/packages/better-auth/src/plugins/organization/routes/crud-org.ts#L718-L727) returns `members[]`, `teams[]`, and `invitations[]` as separate arrays with no relational data connecting them. The [`teamMember` junction table](https://github.com/better-auth/better-auth/blob/35deabdef026f6887eb5dfda539f39460076fad4/packages/better-auth/src/plugins/organization/schema.ts#L77-L98) exists in the database schema and stores the team-member relationships, but the [`findFullOrganization` adapter method](https://github.com/better-auth/better-auth/blob/35deabdef026f6887eb5dfda539f39460076fad4/packages/better-auth/src/plugins/organization/adapter.ts#L578-L583) simply doesn't query or include this data. So you get all the pieces but no way to connect them—which defeats much of the purpose of a "full organization" response. This does seem like a reasonable feature request/bug: either include `teamMembers[]` in the response, add a `teams` array to each member, or add a `members` array to each team. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/6f8280fc-26b5-4441-89a4-1c994c015b1b?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/6f8280fc-26b5-4441-89a4-1c994c015b1b?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/6f8280fc-26b5-4441-89a4-1c994c015b1b?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/6f8280fc-26b5-4441-89a4-1c994c015b1b?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/6f8280fc-26b5-4441-89a4-1c994c015b1b?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/6f8280fc-26b5-4441-89a4-1c994c015b1b?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/6f8280fc-26b5-4441-89a4-1c994c015b1b?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=You%20raise%20a%20valid%20point.%20Looking%20at%20the%20code%20more%20closely%2C%20you%27re%20right%20that%20this%20is%20a%20functional%20gap%20rather%20than%20just%20a%20type%20issue.%0A%0AThe%20%5B%60getFullOrganization%60%20response%5D%28https%3A//github.com/better-auth/better-auth/blob/35deabdef026f6887eb5dfda539f39460076fad4/packages/better-auth/src/plugins/organization/routes/crud-org.ts%23L718-L727%29%20returns%20%60members%5B%5D%60%2C%20%60teams%5B%5D%60%2C%20and%20%60invitations%5B%5D%60%20as%20separate%20arrays%20with%20no%20relational%20data%20connecting%20them.%20The%20%5B%60teamMember%60%20junction%20table%5D%28https%3A//github.com/better-auth/better-auth/blob/35deabdef026f6887eb5dfda539f39460076fad4/packages/better-auth/src/plugins/organization/schema.ts%23L77-L98%29%20exists%20in%20the%20database%20schema%20and%20stores%20the%20team-member%20relationships%2C%20but%20the%20%5B%60findFullOrganization%60%20adapter%20method%5D%28https%3A//github.com/better-auth/better-auth/blob/35deabdef026f6887eb5dfda539f39460076fad4/packages/better-auth/src/plugins/organization/adapter.ts%23L578-L583%29%20simply%20doesn%27t%20query%20or%20include%20this%20data.%0A%0ASo%20you%20get%20all%20the%20pieces%20but%20no%20way%20to%20connect%20them%E2%80%94which%20defeats%20much%20of%20the%20purpose%20of%20a%20%22full%20organization%22%20response.%20This%20does%20seem%20like%20a%20reasonable%20feature%20request/bug%3A%20either%20include%20%60teamMembers%5B%5D%60%20in%20the%20response%2C%20add%20a%20%60teams%60%20array%20to%20each%20member%2C%20or%20add%20a%20%60members%60%20array%20to%20each%20team.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8307)
Author
Owner

@DarkNasuada commented on GitHub (Mar 2, 2026):

@dosu I would prefer a teamMembers array per team

<!-- gh-comment-id:3987687116 --> @DarkNasuada commented on GitHub (Mar 2, 2026): @dosu I would prefer a teamMembers array per team
Author
Owner

@dosubot[bot] commented on GitHub (Mar 2, 2026):

That makes sense—a members array nested inside each team object would be the most intuitive structure for hierarchical data. Something like:

{
  organization: { ... },
  members: [...],
  teams: [
    { id: "team1", name: "Engineering", members: [{ userId: "...", ... }] },
    { id: "team2", name: "Design", members: [...] }
  ]
}

This would make it easy to render team rosters or filter members by team without additional queries. Hopefully a maintainer can weigh in on whether this enhancement fits the roadmap.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3987688914 --> @dosubot[bot] commented on GitHub (Mar 2, 2026): <!-- Answer --> That makes sense—a `members` array nested inside each team object would be the most intuitive structure for hierarchical data. Something like: ```typescript { organization: { ... }, members: [...], teams: [ { id: "team1", name: "Engineering", members: [{ userId: "...", ... }] }, { id: "team2", name: "Design", members: [...] } ] } ``` This would make it easy to render team rosters or filter members by team without additional queries. Hopefully a maintainer can weigh in on whether this enhancement fits the roadmap. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/133e0231-bcea-4be2-8d9e-af88a728a91c?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/133e0231-bcea-4be2-8d9e-af88a728a91c?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/133e0231-bcea-4be2-8d9e-af88a728a91c?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/133e0231-bcea-4be2-8d9e-af88a728a91c?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/133e0231-bcea-4be2-8d9e-af88a728a91c?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/133e0231-bcea-4be2-8d9e-af88a728a91c?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/133e0231-bcea-4be2-8d9e-af88a728a91c?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=That%20makes%20sense%E2%80%94a%20%60members%60%20array%20nested%20inside%20each%20team%20object%20would%20be%20the%20most%20intuitive%20structure%20for%20hierarchical%20data.%20Something%20like%3A%0A%0A%60%60%60typescript%0A%7B%0A%20%20organization%3A%20%7B%20...%20%7D%2C%0A%20%20members%3A%20%5B...%5D%2C%0A%20%20teams%3A%20%5B%0A%20%20%20%20%7B%20id%3A%20%22team1%22%2C%20name%3A%20%22Engineering%22%2C%20members%3A%20%5B%7B%20userId%3A%20%22...%22%2C%20...%20%7D%5D%20%7D%2C%0A%20%20%20%20%7B%20id%3A%20%22team2%22%2C%20name%3A%20%22Design%22%2C%20members%3A%20%5B...%5D%20%7D%0A%20%20%5D%0A%7D%0A%60%60%60%0A%0AThis%20would%20make%20it%20easy%20to%20render%20team%20rosters%20or%20filter%20members%20by%20team%20without%20additional%20queries.%20Hopefully%20a%20maintainer%20can%20weigh%20in%20on%20whether%20this%20enhancement%20fits%20the%20roadmap.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8307)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#11052