Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
218e0fb
feat: add better auth
HimanshuKumarDutt094 Aug 23, 2025
57badda
update: fix better auth error. add: github provider, env.js for bette…
HimanshuKumarDutt094 Aug 23, 2025
5539bee
chore:fix: table name, better-auth working for drizzle + sqlite/postg…
HimanshuKumarDutt094 Aug 23, 2025
33f6521
chore: update cli text
HimanshuKumarDutt094 Aug 23, 2025
dd18808
chore: lint fix + use defaultFn instead of sql
HimanshuKumarDutt094 Aug 23, 2025
e00c389
fix: drizzle adapter provider switch, prisma schema fix
HimanshuKumarDutt094 Aug 23, 2025
38ec93e
update: add better auth setup via cli + tests
HimanshuKumarDutt094 Sep 11, 2025
8b32389
feat: better-auth pages router initial setup
HimanshuKumarDutt094 Sep 11, 2025
93f6835
feat: better-auth pages router setup
HimanshuKumarDutt094 Sep 11, 2025
08f7e94
update: better-auth pages router ui, session type export,todo:update …
HimanshuKumarDutt094 Sep 11, 2025
9d8ade9
chore: lint fix
HimanshuKumarDutt094 Sep 11, 2025
53c7613
chore: format fix
HimanshuKumarDutt094 Sep 11, 2025
429d5ee
fix(ci): using dynamic script for matrix injection (testing)
HimanshuKumarDutt094 Sep 13, 2025
afe95db
checking the output for script
HimanshuKumarDutt094 Sep 13, 2025
c2a73a8
fix: req headers for better auth pages
HimanshuKumarDutt094 Sep 13, 2025
e499f3a
trying to fix prisma generate
HimanshuKumarDutt094 Sep 13, 2025
af98386
fix: prisma schema , feat: new generated output+better-auth only comp…
HimanshuKumarDutt094 Sep 13, 2025
59033ef
fix: add prisma generated to ts exclude
HimanshuKumarDutt094 Sep 13, 2025
8b11944
added missing index page code
HimanshuKumarDutt094 Sep 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eighty-scissors-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-t3-app": minor
---

feat: new better auth setup with drizzle and prisma
54 changes: 54 additions & 0 deletions .github/scripts/generate-matrix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Define all possible values
const options = {
trpc: ['true', 'false'],
tailwind: ['true', 'false'],
nextAuth: ['true', 'false'],
betterAuth: ['true', 'false'],
prisma: ['true', 'false'],
drizzle: ['true', 'false'],
appRouter: ['true', 'false'],
dbType: ['planetscale', 'sqlite', 'mysql', 'postgres']
};

// Generate all combinations
function generateCombinations(opts) {
const keys = Object.keys(opts);
const combinations = [];

function recurse(index, current) {
if (index === keys.length) {
combinations.push({...current});
return;
}

const key = keys[index];
for (const value of opts[key]) {
current[key] = value;
recurse(index + 1, current);
}
}

recurse(0, {});
return combinations;
}

// Filter valid combinations based on current validation logic
function isValid(combo) {
const { prisma, drizzle, nextAuth, betterAuth, dbType } = combo;

// Not both auth true
if (nextAuth === 'true' && betterAuth === 'true') return false;

// Not both db true
if (prisma === 'true' && drizzle === 'true') return false;

// If no db selected, only allow sqlite
if (prisma === 'false' && drizzle === 'false' && dbType !== 'sqlite') return false;

return true;
}

const allCombos = generateCombinations(options);
const validCombos = allCombos.filter(isValid);

console.log(`matrix=${JSON.stringify({include: validCombos})}`);
39 changes: 17 additions & 22 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,47 +20,42 @@ concurrency:
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

jobs:
generate-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.generate.outputs.matrix }}
steps:
- uses: actions/checkout@v4
- name: Generate valid matrix combinations
id: generate
run: node .github/scripts/generate-matrix.js >> $GITHUB_OUTPUT

build-t3-app:
needs: generate-matrix
runs-on: ubuntu-latest
# if: |
# contains(github.event.pull_request.labels.*.name, '📌 area: cli') ||
# contains(github.event.pull_request.labels.*.name, '📌 area: t3-app')
strategy:
matrix:
trpc: ["true", "false"]
tailwind: ["true", "false"]
nextAuth: ["true", "false"]
prisma: ["true", "false"]
appRouter: ["true", "false"]
drizzle: ["true", "false"]
dbType: ["planetscale", "sqlite", "mysql", "postgres"]

name: "Build and Start T3 App ${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }}"
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}

name: "Build and Start T3 App ${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.betterAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }}"
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Check valid matrix
id: matrix-valid
run: |
echo "continue=${{ (matrix.prisma == 'false' || matrix.drizzle == 'false') && (matrix.drizzle == 'true' || matrix.prisma == 'true' || matrix.dbType == 'sqlite') }}" >> $GITHUB_OUTPUT

- uses: ./.github/actions/setup
if: ${{ steps.matrix-valid.outputs.continue == 'true' }}

- run: pnpm turbo --filter=create-t3-app build
if: ${{ steps.matrix-valid.outputs.continue == 'true' }}

# has to be scaffolded outside the CLI project so that no lint/tsconfig are leaking
# through. this way it ensures that it is the app's configs that are being used
# FIXME: this is a bit hacky, would rather have --packages=trpc,tailwind,... but not sure how to setup the matrix for that
- run: cd cli && pnpm start ../../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} --noGit --CI --trpc=${{ matrix.trpc }} --tailwind=${{ matrix.tailwind }} --nextAuth=${{ matrix.nextAuth }} --prisma=${{ matrix.prisma }} --drizzle=${{ matrix.drizzle }} --appRouter=${{ matrix.appRouter }} --dbProvider=${{ matrix.dbType }} --eslint
if: ${{ steps.matrix-valid.outputs.continue == 'true' }}
- run: cd cli && pnpm start ../../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.betterAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} --noGit --CI --trpc=${{ matrix.trpc }} --tailwind=${{ matrix.tailwind }} --nextAuth=${{ matrix.nextAuth }} --betterAuth=${{ matrix.betterAuth }} --prisma=${{ matrix.prisma }} --drizzle=${{ matrix.drizzle }} --appRouter=${{ matrix.appRouter }} --dbProvider=${{ matrix.dbType }}
# can't use default mysql string cause t3-env blocks that

- run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} && pnpm build
if: ${{ steps.matrix-valid.outputs.continue == 'true' }}
- run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.betterAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} && pnpm build
env:
AUTH_SECRET: foo
AUTH_DISCORD_ID: bar
Expand All @@ -87,7 +82,7 @@ jobs:
echo "continue=${{ (matrix.eslint == 'false' || matrix.biome == 'false') && (matrix.biome == 'true' || matrix.eslint == 'true') }}" >> $GITHUB_OUTPUT

- uses: ./.github/actions/setup
if: ${{ steps.matrix-valid.outputs.continue == 'true' }}
if: ${{ steps.matrix-valid.outputs.continue == 'true' }}

- run: pnpm turbo --filter=create-t3-app build
if: ${{ steps.matrix-valid.outputs.continue == 'true' }}
Expand Down
1 change: 1 addition & 0 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"@types/fs-extra": "^11.0.4",
"@types/gradient-string": "^1.1.6",
"@types/node": "^20.14.10",
"better-auth": "^1.3",
"drizzle-kit": "^0.30.5",
"drizzle-orm": "^0.41.0",
"mysql2": "^3.11.0",
Expand Down
16 changes: 16 additions & 0 deletions cli/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ interface CliFlags {
/** @internal Used in CI. */
nextAuth: boolean;
/** @internal Used in CI. */
betterAuth: boolean;
/** @internal Used in CI. */
appRouter: boolean;
/** @internal Used in CI. */
dbProvider: DatabaseProvider;
Expand Down Expand Up @@ -63,6 +65,7 @@ const defaultOptions: CliResults = {
prisma: false,
drizzle: false,
nextAuth: false,
betterAuth: false,
importAlias: "~/",
appRouter: false,
dbProvider: "sqlite",
Expand Down Expand Up @@ -115,6 +118,12 @@ export const runCli = async (): Promise<CliResults> => {
"Experimental: Boolean value if we should install NextAuth.js. Must be used in conjunction with `--CI`.",
(value) => !!value && value !== "false"
)
/** @experimental Used for CI E2E tests. Used in conjunction with `--CI` to skip prompting. */
.option(
"--betterAuth [boolean]",
"Experimental: Boolean value if we should install BetterAuth. Must be used in conjunction with `--CI`.",
(value) => !!value && value !== "false"
)
/** @experimental - Used for CI E2E tests. Used in conjunction with `--CI` to skip prompting. */
.option(
"--prisma [boolean]",
Expand Down Expand Up @@ -199,6 +208,7 @@ export const runCli = async (): Promise<CliResults> => {
if (cliResults.flags.prisma) cliResults.packages.push("prisma");
if (cliResults.flags.drizzle) cliResults.packages.push("drizzle");
if (cliResults.flags.nextAuth) cliResults.packages.push("nextAuth");
if (cliResults.flags.betterAuth) cliResults.packages.push("betterAuth");
if (cliResults.flags.eslint) cliResults.packages.push("eslint");
if (cliResults.flags.biome) cliResults.packages.push("biome");
if (cliResults.flags.prisma && cliResults.flags.drizzle) {
Expand All @@ -212,6 +222,10 @@ export const runCli = async (): Promise<CliResults> => {
logger.warn("Incompatible combination Biome + ESLint. Exiting.");
process.exit(0);
}
if (cliResults.flags.nextAuth && cliResults.flags.betterAuth) {
logger.warn("Incompatible combination NextAuth + BetterAuth. Exiting.");
process.exit(0);
}
if (databaseProviders.includes(cliResults.flags.dbProvider) === false) {
logger.warn(
`Incompatible database provided. Use: ${databaseProviders.join(", ")}. Exiting.`
Expand Down Expand Up @@ -286,6 +300,7 @@ export const runCli = async (): Promise<CliResults> => {
options: [
{ value: "none", label: "None" },
{ value: "next-auth", label: "NextAuth.js" },
{ value: "better-auth", label: "BetterAuth" },
// Maybe later
// { value: "clerk", label: "Clerk" },
],
Expand Down Expand Up @@ -372,6 +387,7 @@ export const runCli = async (): Promise<CliResults> => {
if (project.styling) packages.push("tailwind");
if (project.trpc) packages.push("trpc");
if (project.authentication === "next-auth") packages.push("nextAuth");
if (project.authentication === "better-auth") packages.push("betterAuth");
if (project.database === "prisma") packages.push("prisma");
if (project.database === "drizzle") packages.push("drizzle");
if (project.linter === "eslint") packages.push("eslint");
Expand Down
42 changes: 33 additions & 9 deletions cli/src/helpers/selectBoilerplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,27 @@ export const selectAppFile = ({

const usingTw = packages.tailwind.inUse;
const usingTRPC = packages.trpc.inUse;
const usingNextAuth = packages.nextAuth.inUse;
const usingAuth = packages?.nextAuth.inUse ?? packages?.betterAuth.inUse;
const usingBetterAuth = packages?.betterAuth.inUse;

let appFile = "base.tsx";
if (usingTRPC && usingTw && usingNextAuth) {
if (usingTRPC && usingTw && usingBetterAuth) {
appFile = "with-better-auth-trpc-tw.tsx";
} else if (usingTRPC && !usingTw && usingBetterAuth) {
appFile = "with-better-auth-trpc.tsx";
} else if (usingTRPC && usingTw && usingAuth) {
appFile = "with-auth-trpc-tw.tsx";
} else if (usingTRPC && !usingTw && usingNextAuth) {
} else if (usingTRPC && !usingTw && usingAuth) {
appFile = "with-auth-trpc.tsx";
} else if (usingTRPC && usingTw) {
appFile = "with-trpc-tw.tsx";
} else if (usingTRPC && !usingTw) {
appFile = "with-trpc.tsx";
} else if (!usingTRPC && usingTw) {
appFile = "with-tw.tsx";
} else if (usingNextAuth && usingTw) {
} else if (usingAuth && usingTw) {
appFile = "with-auth-tw.tsx";
} else if (usingNextAuth && !usingTw) {
} else if (usingAuth && !usingTw) {
appFile = "with-auth.tsx";
}

Expand Down Expand Up @@ -72,10 +77,20 @@ export const selectIndexFile = ({

const usingTRPC = packages.trpc.inUse;
const usingTw = packages.tailwind.inUse;
const usingAuth = packages.nextAuth.inUse;
const usingBetterAuth = packages?.betterAuth.inUse;
const usingNextAuth = packages?.nextAuth.inUse;
const usingAuth = usingNextAuth || usingBetterAuth;

let indexFile = "base.tsx";
if (usingTRPC && usingTw && usingAuth) {
if (usingTRPC && usingTw && usingBetterAuth) {
indexFile = "with-better-auth-trpc-tw.tsx";
} else if (usingTRPC && !usingTw && usingBetterAuth) {
indexFile = "with-better-auth-trpc.tsx";
} else if (!usingTRPC && usingTw && usingBetterAuth) {
indexFile = "with-better-auth-tw.tsx";
} else if (!usingTRPC && !usingTw && usingBetterAuth) {
indexFile = "with-better-auth.tsx";
} else if (usingTRPC && usingTw && usingAuth) {
indexFile = "with-auth-trpc-tw.tsx";
} else if (usingTRPC && !usingTw && usingAuth) {
indexFile = "with-auth-trpc.tsx";
Expand All @@ -101,10 +116,19 @@ export const selectPageFile = ({

const usingTRPC = packages.trpc.inUse;
const usingTw = packages.tailwind.inUse;
const usingAuth = packages.nextAuth.inUse;
const usingAuth = packages?.nextAuth.inUse;
const usingBetterAuth = packages?.betterAuth.inUse;

let indexFile = "base.tsx";
if (usingTRPC && usingTw && usingAuth) {
if (usingTRPC && usingTw && usingBetterAuth) {
indexFile = "with-better-auth-trpc-tw.tsx";
} else if (usingTRPC && !usingTw && usingBetterAuth) {
indexFile = "with-better-auth-trpc.tsx";
} else if (!usingTRPC && usingTw && usingBetterAuth) {
indexFile = "with-better-auth-tw.tsx";
} else if (!usingTRPC && !usingTw && usingBetterAuth) {
indexFile = "with-better-auth.tsx";
} else if (usingTRPC && usingTw && usingAuth) {
indexFile = "with-auth-trpc-tw.tsx";
} else if (usingTRPC && !usingTw && usingAuth) {
indexFile = "with-auth-trpc.tsx";
Expand Down
6 changes: 6 additions & 0 deletions cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ const main = async () => {
if (!noInstall) {
await installDependencies({ projectDir });

if (usePackages.prisma.inUse) {
logger.info("Generating Prisma client...");
await execa("npx", ["prisma", "generate"], { cwd: projectDir });
logger.info("Successfully generated Prisma client!");
}

await formatProject({
pkgManager,
projectDir,
Expand Down
Loading