Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 15 additions & 9 deletions src/tasks/setup-prisma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const DEFAULT_PRISMA_POSTGRES = true;
const DEFAULT_INSTALL = true;
const DEFAULT_GENERATE = true;
const DEFAULT_MIGRATE_AND_SEED = true;
const PRISMA_POSTGRES_MIGRATION_DELAY_MS = 2000;
const PRISMA_POSTGRES_MIGRATION_RETRY_DELAYS_MS = [1000, 2000, 4000];

const requiredPrismaFileGroups = [
["prisma/schema.prisma", "packages/db/prisma/schema.prisma"],
Expand Down Expand Up @@ -851,15 +851,21 @@ async function migrateAndSeedIfRequested(
migrateSpinner.start("Creating and applying initial migration...");
let didMigrate = false;
try {
if (context.shouldUsePrismaPostgres) {
// Newly provisioned Prisma Postgres databases can briefly reject the first migration.
// TODO(2026-04-26): replace this grace period with an explicit readiness probe.
await new Promise((resolve) => setTimeout(resolve, PRISMA_POSTGRES_MIGRATION_DELAY_MS));
for (let attempt = 0; ; attempt++) {
try {
await execa(migrateInvocation.command, migrateInvocation.args, {
cwd: prismaProjectDir,
stdio: context.verbose ? "inherit" : "pipe",
});
break;
} catch (error) {
const retryDelayMs = PRISMA_POSTGRES_MIGRATION_RETRY_DELAYS_MS[attempt];
if (!context.shouldUsePrismaPostgres || retryDelayMs === undefined) {
throw error;
}
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
}
}
await execa(migrateInvocation.command, migrateInvocation.args, {
cwd: prismaProjectDir,
stdio: context.verbose ? "inherit" : "pipe",
});
migrateSpinner.stop("Initial migration applied.");
didMigrate = true;
} catch (error) {
Expand Down
25 changes: 14 additions & 11 deletions templates/create/astro/astro.config.mjs.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,23 @@
import { defineConfig } from "astro/config";
import node from "@astrojs/node";

// Workaround for cookie CJS imports on Prisma Compute's Bun runtime; build-only because noExternal breaks `astro dev`.
/** @type {import("astro").AstroIntegration} */
const bundleSsrDependenciesOnBuild = {
name: "bundle-ssr-dependencies-on-build",
hooks: {
"astro:config:setup": ({ command, updateConfig }) => {
if (command === "build") {
updateConfig({ vite: { ssr: { noExternal: true } } });
}
},
},
};

// https://astro.build/config
export default defineConfig({
output: "server",
adapter: node({ mode: "standalone" }),
server: { host: true },
vite: {
ssr: {
// Bundle SSR dependencies into the server entry. Astro's standalone
// build emits `import { parse, serialize } from "cookie"`, and the Bun
// runtime on Prisma Compute cannot resolve those named exports from
// cookie's CommonJS build at runtime (SyntaxError: Export named 'parse'
// not found). Bundling resolves the imports at build time. Remove once
// the Bun/cookie CJS named-export interop is fixed upstream.
noExternal: true,
},
},
integrations: [bundleSsrDependenciesOnBuild],
});
4 changes: 2 additions & 2 deletions templates/create/next/package.json.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"lint": "eslint"
},
"dependencies": {
"next": "16.2.9",
"next": "16.2.10",
"react": "19.2.7",
"react-dom": "19.2.7"
},
Expand All @@ -22,7 +22,7 @@
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"eslint": "^10.5.0",
"eslint-config-next": "16.2.9",
"eslint-config-next": "16.2.10",
"tsx": "^4.22.4",
"typescript": "^6.0.3"
}
Expand Down
2 changes: 1 addition & 1 deletion templates/create/turborepo/apps/api/package.json.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
{{else}}
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/src/index.js",
"start": "tsx src/index.ts",
"typecheck": "tsc --noEmit"
{{/if}}
},
Expand Down
14 changes: 11 additions & 3 deletions templates/create/turborepo/packages/db/src/client.ts.hbs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{#unless (eq packageManager "deno")}}
import path from "node:path";
import { fileURLToPath } from "node:url";
{{#unless (eq packageManager "deno")}}
import dotenv from "dotenv";
{{/unless}}
import { PrismaClient } from "./generated/prisma/client{{#if (eq packageManager "deno")}}.ts{{/if}}";
Expand All @@ -20,14 +20,22 @@ import { {{sqliteAdapterClass packageManager}} } from "{{sqliteAdapterPackage pa
import { PrismaMssql } from "@prisma/adapter-mssql";
{{/if}}

{{#unless (eq packageManager "deno")}}
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
{{#unless (eq packageManager "deno")}}
dotenv.config({ path: path.resolve(moduleDir, "../.env"), quiet: true });
{{/unless}}

const rawDatabaseUrl = process.env.DATABASE_URL;
{{#if (eq provider "sqlite")}}
const databaseUrl = (rawDatabaseUrl ?? "").trim() || "file:./dev.db";
function resolveSqliteUrl(url: string): string {
const filePath = url.replace(/^file:(?:\/\/)?/, "");
if (!url.startsWith("file:") || path.isAbsolute(filePath)) {
return url;
}
return `file:${path.resolve(moduleDir, "..", filePath)}`;
}

const databaseUrl = resolveSqliteUrl((rawDatabaseUrl ?? "").trim() || "file:./dev.db");
{{else}}
const databaseUrl = (rawDatabaseUrl ?? "").trim();
if (!databaseUrl) {
Expand Down
1 change: 1 addition & 0 deletions templates/create/turborepo/turbo.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"$schema": "https://turbo.build/schema.json",
"globalPassThroughEnv": ["PORT", "DATABASE_URL"],
"tasks": {
"build": {
"dependsOn": ["^build"],
Expand Down
Loading